반응형

요즘 관심사가 Multi-process, 상의 Windowing system이다 보니, 이런 저런 자료들을 찾아보게 되는데,
제 입장에서 가장 쉽게 접할 수 있는 System이 Windows의 windowing system과 linux 의 windowing system이더군요.

저도 제가 쓰는 OS가 Windows 이고, 학생때 주로 Windows 프로그래밍을 하다보니, embeded 에서도 어떤 모듈을 개발해야 될때 밴치마킹을 windows로  했었습니다.
"화면복원을 windows에서는 어떻게 구현했을까? Clipboard를 만들생각인데, MSDN에서 한번 찾아볼까? " 대충 이런식 이죠.


Windowing System이란?

기본정의는 application의 GUI를 사각형 영역(window, 창) 안에 image나 pixel, text, color등으로 표현하는 것을 의미합니다.
따라서 application process 를 창으로 표현하기 때문에 사용자가 여러개의 application을 동시에 사용해야 하는 경우에 직관적으로 접근할 수 있도록 해주는 system입니다.

많은 platform들이 이 Windwing system이라는 컨셉을 사용하고 있는데, 몇가지 platform들을 나열해보자면, windows나 linux, mac, andriod 등 우리가 알고 있는 대부분의 OS들이 이에 해당합니다.
너무 기본컨셉에 대한 내용이라 다들 아는 내용일텐데, 설명하려니 좀 까다롭네요.

이 window라는 컨셉은 software프로그램을 표현하기 위한 GUI로서는 지금 생각해봐도 멋들어진 컨셉이라 생각됩니다.
mouse와 함께 양대 산맥이라 해도 좋을 만큼요.

요즘에야 당연하게 생각되는 것이기도 합니다.

그때문에 요즘에 만들어지는 application framework 들도 대부분 window를 기반으로 Control이라는 컨셉을 적용하는 것을 기본으로 합니다.
물론 이런 컨셉이 아닌 Model - Control - Presentation을 base로 구성하려는 움직임도 있기는 합니다만, 아마도 가번 system은 windowing system으로 하고 그 위에 올라가는 SDK 차원에서 지원을 windowing system premetive 한 API들 뿐만아니라, 확장된 개념으로 제공하는 경우가 많습니다.
OSX, Windows series, Symbian, Linux X-Window, BeOS, NEXTSTEP 등등 모두다 window 기반의 시스템이죠.

이 외에도 in-house 방식으로 개발되는 대부분의 platform들도 아마 windowing system을 적용하려 한다고 보입니다.
( 아닌 system도 있기는 하죠, 저도 몇번 경험했었으니..)

PalmFree는 인터넷에 올라온 기사에서 읽은 바로는 HTML base의 OS라고 하는데,제 생각에는 base에는 windowing system이 깔려있지 않을까 합니다. 정확한 내용은 아니니 요거는 살짝 꼬리 내리고 가겠습니다. ㅎ

아무튼 지금까지 나온 System들은 대부분 GUI를 표현하기 위해서 windowing system을 사용하고 있다는 것이고, 제가 개발하고자 하는 것도 이러한 windowing system 이랍니다.


Windowing System 공부하기?
우선 저는 X-window 와 GTK를 스터디 하려고 합니다.
X-Server나 GTK는 수년 십수년 동안 안정화를 해 나가고 있는 system인데다가, Source까지 open되어있기 때문에 실제 구현이 어떤식으로 되어있는지 를 확인 할수 있으리라 예상되기 때문인데요, 더군다나 windows 의 경우에는 제가 평소 사용하고 자주 접하고 있는 system이다 보니 대충 동작방식은 이해를 하고 있는 상태이기 때문에 특별히 더 공부가 필요하다고 생각되지 않는것도 하나의 이유입니다.(더군다나 windows는 소스가 없으니 상상만 하게되죠.)
 
이런 생각에 처음 받아본 소스가 xorg-server-1.4.tar 를 첨 받았답니다.
압출을 풀고 소스를 쭉 살펴보니,,
XServer.h 라는 파일이 있어 ... "오 요파일은 뭔가 중요해 보이는 구나.." 싶어 파일을 열어봤는데.
흑..
#import <Cocoa/Cocoa.h>
@interface XServer : NSObject {
:
로 시작되더군요.

OSX 의 Cocoa framework에서 사용되는 XServer.h 인가봅니다.
"OSX도 X server를 사용하나 보군...." 요런 생각을 했습니다.

그러면서 다시 source file에 대한 keyword를 생각하다보니. window 를 찾게 되었는데, win 까지 typing을 하고니니. win.h 가 보이더군요.
hw/xwin/win.h 뭔가 스터디를 해야할 첫 포인트를 찾은 느낌이랄까.
(사실 제가 X-Window를 한번도 공부한적이 없어서 인터넷을 선생님 삼아 시작을 해보고 있는 것이라 이리 삽질이 많답니다.)

WinWindow.c
코드 분석 .
일단 전체적인 함수들의 종류를 살펴봤다. ( 함수 살펴보기에는 h 파일들이 더 좋음... ^^;;)
그런데, WinWindow.c 에 구현되어있는 함수들의 선언은 대부분 win.h에 있더군요. WinWindow.h에는
CreateWindow,DeleteWindow , DestroySubwindows ,GravityTranslate, MoveWindowInStack,CheckWindowOptionalNeed,FindWindowWithOptional
GravityTranslate 왠 Gravity?????




암튼 책에서 본 함수들과 좀 달라서.. 더 코드를 살펴보고, X Window의 비밀(????) 을 탐구하기로함.







반응형

불확실한 것 투성이인 S/W 개발을 정량화 하여 언제 완료 된다고 감히 말한다는 것은 참으로 어려운 일이다.
더군다나 본인이 직접 개발을 하는 상황이 아니라 여러 팀원들과 진행하면서 "다른 사람이 이일을 얼마만에 해 낼 것이다" 라고 추정하기란 더더욱 어렵다.

프로젝트 미팅을 들어가면 항상 이런 패턴이다.

프로덕트 기획자: 우리 이러한 제품을 만들어야 하는데요. 개발실에서는 어떻게 생각하시나요.
             ( 프리젠테이션을 멋지게 보여준다.)
개발자들 : <속으로>허걱~ 완전 상상의 나래를 펼치셨네.
개발자들 끼리 의견 분분~
개발자 중 한사람: 그거 음 이렇게 하면 되지 않을까요?
                    (솰라 솰라~~ 구현에 대해서 자신이 생각하는 방향을 열씸히 예기 한다.)
다른 개발자: 음 그런데 지금 구조에서는 잘 안될것 같은데 새로 뭔가 만들거나, 지금껄 많이 엎고 작업 다시 하는 것도 생각해봐야 겠네요.

그리고 한참동안 개발자들은 나름대로의 상상속에 빠져서 자기가 생각하는 구현 방법, 문제점 등등을 즉시 예기하기 시작한다. ㅎ
이미 설계는 시작되었다~~~!!!!
이 와중 찬물을 끼언는 소리~~~~

프로젝트 리더: 그럼 언제까지 돼?
개발자들 : ...


참으로 언제까지 된다는 예기를 하기가 점점 힘들어지는 것이 개발자의 입장이다..!!!
경험이 쌓이면 쌓일 수록 쉬워야 되는 것인데도 불구하고 점점 요구되는 S/W의 스팩도 높아지고, 복잡도도 높아지고 있어서 결정하기가 점점 어려워지게 된다.

이런 업무 범위 추정과 계획은 프로젝트의 성공과 상품화 전략을 위해서 매우 중요한 부분이다.

에자일에서는 이러한 업무의 process를 나누는 단위를 "스토리","이터레이션" 이라는 이름으로 사용하고있다.

스토리는 업무의 조각에 해당하는 것이고, 이터레이션은 수행기간을 단위화 한 것이다.

프로젝트의 초기 셋업에서 가장 중요한 것은 개발 일정 산출일 것이다.
하지만 개발일정이라는 것은 각 모듈의 개발 기간과 투입 리소스를 산출해야 하는데 이를 정확히 산출해 내서 계획을 새운다는 것은 사실상 리스크를 더 갖게 만든다.
이유는 개발 기간을 산출하는 사람이 개발자라 할지라도 개발 기간중 어떻한 일이 발생할 것인 지도 모르는 상황에서 이건 언제 끝나고 이건 언제 끝난다 라고 답하는 것은 힘들기 때문이다.
또 만약 개발자가 개발해본 경험이 없는 모듈이라고 한다면 사실 개발 기간을 정리 하는 것도 무리일 수가 있다.

그럼에도 불구하고 프로젝트가 움직 이기 위해서는 개발팀은 개발기간을 산출 해야 한다.

이런 확실하지 않은 개발 기간 산출을 "추정"이라 하고 이를 얼마나 효과적으로 가능한한 현실 적으로 정리 하는 가를 "추정의 기술" 이라 하겠다.
(마치 "싸움의 기술" 같은 느낌?ㅎ )

우선 프로젝트의 기간을 추정하는 작업은
가장 먼저 프로젝트의 규모를 추정하는 작업에서 시작된다.
만약 이전에 이미 팀의 프로젝트 진행 속도를 알고 있다면, 추정하기가 편해진다.
스토리 단위로 개발을 진행 한 경험이 있다고 한다면, 팀의 속도가 더욱더 분명해진다.

이로 인해 개발전에 프로젝트 전체의 추정치가 나오게 되고, 실제 개발에 들어가게 되면, 이 추정치를 바탕으로 실제 개발 범위와의 오차를 조절해야 한다.

예를 들면 , 이러한 것이다.

자동 운전 시스템을 개발하고자 할때 Story를 다음과 같이 정했다고 하자.
운전 시스템 모듈 100점
도로 주행 모듈 150점
주행 경로 모듈 50점

이렇게 총 300점의 개발 프로젝트 라고 초기에 추정했다고 하자. 그래서 이전에 개발팀의 속도로 보아 100 점을 4회의 이터레이션에 처리했다면 약 12회의 이터레이션에 해결할 수 있는 프로젝트 라고 생각 할 것이다.(1회에 25점의 스토리를 처리했다.)

그런데 막상 개발을 시작하고 보니, 1회 이터레이션에 10점 정도의 스토리 밖에 처리가 되지 않았다 라고 한다면, 우리는 15점을 처리 못하고 남겨 놨다는 것을 알게된다. 때문에 우리 개발기간은 1.5배 길어질 것이라는 것을 예상 할 수 있다.

그렇다면 초기 추정치가 쓸모 없는 것이 되는가?
그렇지 않다! 그렇게 되도록 둬서는 안된다.
무슨 의미인가 하면 우리는 흔히 개발 spec을 산출할때 기간을 중심에 두는 경우가 많다.
이건 몇일 걸리고 이건 몇일 걸리고, 이런 식으로 말이죠.
이렇게 생각해서 스토리에 점수를 줬다고 한다면, 많은 부분이 다시 수정되어야 한다.
그러면 스토리 점수는 무엇이어야 하는가?
일의 크기로 생각해야 한다. 일의 범위는 모듈의 개수,class의 수, 코드량, 난이도, 등등을 생각해서 점수를 줬다면
전체적인 일의 크기가 정해지게 된다. 일의 크기가 얼마인가와 이를 해결하는데 얼마가 걸리는 것인지는 다르다.

일의 크기를 단위로 나누게 되면, 각 스토리 간의 난이도 비교가 된다.
즉 10의 점수를 갖는 스토리는 5의 점수를 갖는 스토리보다 배는 어렵다는 것이다.
또 10의 점수를 갖는 스토리는 20의 점수를 갖는 스토리보다 반은 쉽고 간결하다는 것이 된다.

이는 10의 점수를 갖는 스토리가 얼마가 걸리는가 하는 문제와는 별개라는 것을 다시한번 강조하고 싶다.

이전 프로젝트에서는 25의 점수가 1 이터레이션이 걸렸지만 , 이번 프로젝트에서는 10의 점수가 1이터레이션이 걸릴 수도 있다는 것이다.
(대부분 반대의 경우가 많다. 이유는 프로젝트 경험이 쌓일 수록 개발 속도는 빨라지기 때문에 지난번 프로젝트에서는 20점이 1 이터레이션이었지만 이번에는 30점을 1이터레이션 내에 끝낼 수 있을 것이다.)

또 점수를 측정함에 있어서도 개발자의 질이 향상되면 그만큼 점수도 유동적으로 변하게 된다.




추정치의 값은 이런 값을 사용해라.

1,2,3,5, 그리고 8 
1,2,4, 그리고 8  큰 단위의 작업에 대한 추정을 할때 , 이 값을 사용하게 되면 보다 큰 불확실성에 대한 대처가 쉽다.

숫자의 간격이 있게되면, 장점은 이렇하다, 3보다는 크고 4보다는 작은 약 3.5 정도 되는 것 같은 스토리의 경우에, 3이라고 작성하면 된다.
이렇게 함으로 해서 복잡해지는 스토리 점수를 막을 수 있다.
실제 우리 업무가 3이라고 작성했지만 3.5가 될 소지가 매우 크기 때문이다.

'0'이라는 값을 추정치에 포함하겠다라고 하면 어떤 일을 0으로 정할 것인지를 고민해야 한다.
(실제로 0을 포함 시키면 프로젝트 추정에 많은 도움이 될 수 있다.)

0이라는 값은, 작업은 필요하지만 매우 간단하여 프로젝트 수행에 영향을 미치지 않는 것을 의미한다.
(또는 자동으로 해결되는것 - 이런 경우는 매우 적지요)

0이라는 값을 사용함에 있어서 먼저 팀원들의 인식을 확실히 해야 한다.
0 이라고 해서 일이 없는 것이 아니기 때문에, 0점짜리 스토리를 한꺼번에( 13x0해서 한 이터레이션 안에서 ) 처리 할 수는 없다.
0은 공짜 점심처럼 한 이터레이션 안에 처리 할 수 있는 작은 업무이지만, 공짜 점심은 개수 재한이 있다는 것을 인식 시킬 필요가 있습니다.
만약 이렇게 많은 0점짜리 스토리를 한번에 처리하고 싶다면, 이들을 묶어서 1점 이상 되는 이터레이션으로 묶어야 합니다.


반응형

회사에서 정말 믿기 어려운 결정(?시도라 하는게 맞을려나?)을 시행했다.

바로 !!!!  자율 출근제 이다.
그럼 자율 출근제란 무엇이냐?  한마디로 "님 맘대로 출근해서 8시간만 때워 주십쇼" 라는 것입니다. ㅎ
몇몇 부서에서 시범 운영을 했는데 결과가 어찌 나왔는지는 잘 모르겠는데.
우리 부서까지 시행을 하다니 꿈만 같다!!...

그리고 오늘이 바로 그 첫날!!!!!
오늘의 느낌을 예기해 보자면,
평소와 비슷한 6시 40분에 알람에 맞춰 눈을 떴습니다.
평소같으면 "10분더자고 50분에 일어나서 씻고 출근준비하거나,
몸이 찌뿌둥하면 10분 더자고 7시부터 급하게 씻고 출근준비하거나,
그래도 월요일이라 더 찌뿌둥하니 10분 더자고 안 씻고 출근하고 ㅡㅡ;;;; "
의 패턴을 보였겠지만!! 오늘은 달랐습니다.

회사생활에서 출근시간의 압박이란 회사를 오래다니면 다닐 수록 늘어나는것 같은데요.
오늘만큼은 그런것이 없었던것 같습니다.
그냥 8시 30분 쯤 일어나서, 약간 빈둥거리다가, 음악 틀어놓고 씻고 청소 조금 하고,
그렇게 출근했습니다. 너무 여유로와서 밑에 슈퍼마켓 가서 우유하나 사먹고,
슈퍼 아저씨랑 썰좀 풀고, 그러고 출근했는데요.

아!!! 출근시간의 압박이 사라지자 뭔가 생활이 달라질것 같군요.!

이게 오전까지의 생각이었습니다.
----------------------------------------------------------------------
점심 후!
오전이 좀 허무하게 날아가 버린것같더군요.
자율 출근이 시작되었으니 예전보다 더 시간 관리를 잘해야 겠다는 생각이 드는군요.



'일상' 카테고리의 다른 글

나의 라임 오렌지나무  (0) 2009.09.15
아 회사가기 싫다!!!  (0) 2009.09.15
와!!! 클릭수 2300번~~  (0) 2009.02.24
자 청소 시작!!!! 워..  (0) 2009.02.01
수원 인계동 트윈파크 오피스텔 46평형 ㅡㅡ;; 구조도  (2) 2009.02.01
반응형

'Link' 카테고리의 다른 글

bada 어플 개발자들 블로그 링크  (0) 2010.05.21
Palm OS developr link  (0) 2009.02.18
[For M4800] Smart phone , MITs , Window Mobile, Finedrive  (0) 2009.01.30
Nokia wiki  (0) 2009.01.20
반응형


<출처 ⓒ designflux.co.kr>


모바일(핸드폰 S/W) 에서만 너무 오래 있었는지 그동안 생각이 많이 굳어있었다 는 것을 세삼 느끼게 해주는 내용의 기사였습니다.

www.designflux.co.kr

이사이트는 자주 다녀서 머리좀 식힐만 한것 같습니다.



MIT’s wearable ‘Sixth Sense’ device
무엇이든 스크린이 된다

눈 앞에 보이는 무엇이든 인터페이스가 된다. MIT 미디어 랩의 패티 메이즈(Patti Maes) 교수가 개발중인 착용식 인터페이스 기기, ‘식스센스(The Sixth Sense)’라면 가능한 일이다. 이 장비를 착용하면 벽이나 책상, 손바닥, 신문 등, 주변의 환경과 사물들이 상호작용 가능한 스크린으로 변신한다.

‘식스센스’는 카메라, 프로젝터, 거울, 손가락 끝에 착용하는 컬러 마커 그리고 모바일 컴퓨팅 기기 등으로 구성되어 있다. 인터페이스로 사용할 수 있는 어떠한 표면에든 프로젝터로 시각 정보를 영사하고, 카메라는 컬러 마커로 표지된 손의 움직임과 제스처를 포착해낸다. 컴퓨팅 기기에서는 이 동영상 데이터를 처리하여, 컬러 마커로 표식된 기점들의 움직임과 배열을 해석하여 실제 인터랙션을 가능케 한다. 이러한 원리로 손으로 사각형을 그리면 사진을 촬영한다거나 하는 일이 가능해지며, 이렇게 촬영한 사진은 곧바로 영사해 확인할 수도 있다. 또한 공중에 아이콘이나 심볼을 그려 특정한 기능에 접속할 수도 있다. 가령 @를 그리면 바로 메일함에 접속하는 식이다.


단돈 350달러로 제작된 ‘식스센스’의 프로토타입은 그 모양새는 상당히 거친 편이지만, 디지털과 현실의 경계를 허물며, 온라인 공간의 데이터를 실제 환경 속 어디에나 불러내 처리할 수 있다는 점에서 주목할 만한 시도다. 아래 ‘식스센스’의 홈페이지를 방문하면 상세한 정보들을 확인할 수 있으며, 관련 사진 자료 및 동영상 자료들도 살펴볼 수 있다.


'개발 Note > it 이야기' 카테고리의 다른 글

설계에 부담갖지말자  (0) 2009.12.06
__asm int 3;  (0) 2009.09.25
[C++ 리플렉션] MFC의 CRuntimeClass  (19) 2009.04.21
소프트웨어, 공학일까? - 재사용성  (1) 2009.02.24
Android - developer  (0) 2009.02.23
반응형

제가 하는 업무가 Platform 이나 Framework을 개발하는 것이기 때문인지 , 어떤 기능이 있었으면 좋겠다는 아이디어가 떠오르거나 막히는 문제가 발생하면, 음, "Windows OS에서는 어떻게 처리했지?" 라는 질문을 던지고 답을 찾아보게 됩니다.

최근에 Open Platform으로 갖춰야 할것 중 하나가 개발 툴인데,
IDE같은 개발 툴들은 대부분 Import, Plug-in, User Defined Control(ActiveX control) 등과 같이, 툴이 만들어지고 나서 새로운 class 나 객체들을 자연스럽게 설치, 추가하여 사용할 수 있도록 해주는 부분들이필요 하게 됩니다.

이런  framework  구현부는 실제 class의 실체를 모른 상태에서 runtime시에 binding 되는 class의 객체를 생성하는 기술이 필요하게 됩니다.

 

class의 인스턴스 생성방법은 다들 알다시피 new를 통해 생성합니다.

BaseClass * pInstance = new SubClass;  

 

바꾸어 말하면 우리는 반드시 SubClass를 알고 있어야 한다는 것입니다. 그래야만 instance를 생성 할 수 있습니다.

아래와 같이 CameraPlugIn class를 framework에서 모르는 상태라고 한다면 절대 instance를 만들 수 없다는 예기죠.

IPlugIn * pPlugIn = new CameraPlugIn;  

만약 우리가  CameraPlugIn를 모르는 상태 즉,  PlugIn Framework 개발당시에는 CameraPlugIn이라는 class를 모르는 상태에서  camera.dll또는 lib을 download받아서, 이를 link 또는 load 해서 사용할 수 있는 기능을 제공하려 할때,
class를 모르는 상태에서 class 를 runtime시에 동적으로 이름이 무엇인지, 알아내서 instance를 생성할 수 있도록 하는 기술이 필요하게됩니다.

이러한 기술을 리플렉션( Reflection) 이라한다.

 

C# 에서도 이와같은 리플렉션은 지원하고 있고, Runtime중에 type binding을 지원하는 Dynaimc 이라는 새로운 타입이 추가될 예정이라고 합니다.

 

그외  루비, 스몰토크, PHP, 파이썬, 펄 등의 언어에서는 리플렉션 객체를 제공하며, 대부분 유사한 형태를 띄고 있습니다.

 


 

아쉽게도 C++ 에서는 공식적으로 지원하지 않는 기능이지만, 전세계의 수많은 똑똑한 개발자 분들이 이런 기능을 다양한 방법으로 제공하고 있습니다.

 

MFC의 CRuntimeClass는 리플랙션과 비슷한 기능을 위해 만들어진 가벼운 Macro 정도이고 실제 훨씬 파워풀하고 플랙서블한 그런 library들도 많이 있으니 관심이 있다면 구글링으로 찾아보셔도 좋을 것입니다.

 


 

그중 하나의 기술 (?, 그렇죠 말그대로 Programming 테크닉이라 불리울 만한 기술이죠. )MFC에서 Runtime class 라는 것이 있습니다.

 


저도 나름 이와 비슷한 아이디어를 떠올리면서 구현을 했었는데 , 거의 구현이 완료되고 나서 생각해보니 MFC에 이런게 있었다는 것이 생각이나, Source code를 뒤져봤답니다.

역시나 이미 상용화되어서 아주 ~~ 아주 잘 쓰고 있는 메크로들이라 그런지, 제가 생각했던 개념과 유사한 뼈대위에 많은 살들이 붙어있더군요.

회사에서 사용하기 위해 작성한 코드가 좋은 예가 될수 있을텐데, 회사의 자산이라 공개를 할 수 없어서  MFC의 Runtime class의 내용을 살펴보는 것으로 대신 하겠습니다.

저는 사실 한 일주일 전쯤 해서  이런 고민에 빠져 있었습니다.

만약 내가 개발 툴을 만들어주고, application 개발자는 자기가 짠 class를 이 개발툴에 plug-in 한 후에 ,
개발 툴에서 재공하는 Generator 를 이용해  Generator("TestClass") 라고 하면 testclass의 instance를 만들어준다고 합시다.
이때 개발툴을 개발할 당시에는 TestClass를 모르고 있기 때문에 일반적인 개발 방법으론, 이를 구현할 수가 없습니다.
즉, Runtime 중에 class를 register하고 이를 parsing하여 instance를 생성 시킬 수 있는 기술이 필요하다.!!

class라는 게 어찌 보면 type인데, 내가 type을 모른 상태에서 object를 생성할 수 있을까?
예를 들면
Object* pA = CreateInstance("TestClass");
라고하면 pA는 class TestClass 로 생성이되는 이런걸 만들고 싶었습니다.
하지만 흔히 이렇게 사용할 수 있으려면, 기본적으로 TestClass를 CreateInstance 내에서 알고 있어야 합니다. 
그래야 "TestClass" 라는 스트링을 parsing한 다음에 TestClass로 생성을 해줄 수가 있기 때문입니다.
그래서 대부분 아래 처럼 머리속에서 코딩을 하겠죠?

 

Object* CreateInstance(char* pClassName) {        
	:
    if(strcmp(pClassName,"TestClass")==0)
    	return (Object*)new TestClass; 
}

CreateInstance를 제너럴하게 만들고 싶어서 pClassName 으로 들어오는 class이름이 무엇이든간에 이에 맞는 class를 찾아서 있으면 해당 class의 instance를 생성해주고, 없으면 null 을 return하기를 원한다면? 어떻게 만들까? 음... class들을 관리하는 table과 class name,그리고 class generator을 만들어서 구현 할 수 있을것 입니다.

Object* CreateInstance(char* pClassName) {
	:        
    for(;;){
    	if(strcmp(pClassName,gClassTable[i].szName)==0)
        	return (Object*) gClassTable[i].Construct(); 
    }
 }

그런데, CreateInstance라는 함수를 만들때는 "TestClass라는 것이 없는데 , 앞으로 누군가가 만들것이다." 라고 한다면? 흠 흠.. 이경우는 난감한가요? 분명 이렇게 되어야 합니다. gClassTable 에 RegisterClass라는 API를 만들어서 이름과 생성자를 등록하여 사용할 수 있도록 해야합니다.

void RegisterClass(char* classname, Object *(*fpConstruct)()) {
	:     
    gClassTable[i].szName = classname;
    gClassTable[i].Construct= fpConstruct; 
 }

헌데 이렇게 되면 상당히 귀찮아지는 것이 fpConstruct를 만드는 일이 됩니다. 개발자의 손이 덜가고 오류를 줄이려면 형식을 제한해야 하는데요.

이를 구현하기 위해서 MFC에서는 runtime class라는 개념이 만들어지게 됩니다. MFC의 CRuntimeClass를 살펴보면, 클레스 전체를 살펴보면 좋겠지만.. 대충 필요한 것들.. 핵심이 될만한 것들만 언급하자면,

struct CRuntimeClass {
// Attributes 
    1) LPCSTR m_lpszClassName; 
    2) CRuntimeClass* m_pBaseClass; 
    3) CObject* CreateObject(); 
    4) static CObject* PASCAL CreateObject(LPCWSTR lpszClassName); 
    5) CRuntimeClass* m_pNextClass;       // linked list of registered classes 
}

아마 가장 핵심이 되는 것이 위의 1)~4) 까지의 내용일 겁니다. 왜냐? 다음 RuntimeClass를 만드는 메크로들을 보면 알 수 있습니다.

#define RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name)) #define DECLARE_DYNAMIC(class_name) \
public: \
    static const CRuntimeClass class##class_name; \
    virtual CRuntimeClass* GetRuntimeClass() const; \
    #define _DECLARE_DYNAMIC(class_name) \
public: \
    static CRuntimeClass class##class_name; \
    virtual CRuntimeClass* GetRuntimeClass() const; \
    #define IMPLEMENT_RUNTIMECLASS(class_name) \
    const CRuntimeClass class_name::class##class_name = { \ 
    	#class_name, sizeof(class class_name), \
	}; \
CRuntimeClass* class_name::GetRuntimeClass() const \
	{ return RUNTIME_CLASS(class_name); } \

이런 메크로들이 있습니다. 약간 길죠?. IMPLEMENT_RUNTIMECLASS 는 설명하기 귀찮은 것들은 다 뺐습니다. 이렇게 메크로만 보면 "뭐하자는 거지?" 라고 의문이 드는 것들이 실제 사용하는 예를 보면 "아하!!" 라고 하게 됩니다.

//in MyTestControl.hpp
//---------------  
class MyTestControl {
  _DECLARE_DYNAMIC(MyTestControl)   //<-- static const Runtimeclass  classMyTestControl 가
                                    // MyTestControl class안에 정의된다.     
        :    
        :
};

 

//in MyTestControl.cpp
//---------------  
//파일 맨 위에 
IMPLEMENT_RUNTIMECLASS(class_name) 
// static 객체인 MyTestControl::classMyTestControl 를 초기화 한다.

//in MyTestApp.cpp  
void main(void) {    
  AfxInitClass(RUNTIME_CLASS(MyTestControl));
  CRuntimeClass::CreateObject("MyTestControl");
}

대충의 설명을 하자면 ,
1. Runtime class로 선언하고자 하는 class 내부에

DECLARE_DYNAMIC(classname)

을 해주고나면, static runtime class 하나가 생기는데

"class"+classname

의 형태로 된다.
2. 이 "classMyTestControl"라고 새로 만들어진 static runtimeclass 는 멤버함수인

3).의 CreateObject()

를 MyTestControl를 생성할 수 있는 함수로 만든다.
3. 그 형식은 아래와 같다.

CreateObject()  {   return new MyTestControl; } 

따라서 우리는 메크로에 의해 생성된 classMyTestControl 이라는 runtime class를 이용해서 MyTestControl이라는 class의 instance를 생성할 수 있게 됩니다.

 

 마지막으로 한가지 설명 안하고 넘어간 것이 있는데.

5) CRuntimeClass* m_pNextClass;       // linked list of registered classes 

이 녀석에 대한 내용이다. 이게 왜 있는가? 제가 개발할때, 위와 같은 구현을 완료하고 나서 Register 단계( MFC에서는 AfxInitClass 단계일듯하다.)에서 결국 table을 만들고, table과 Runtime class를 묶는 작업을 하고, search하는 함수를 만들고... 등등을 작업했었다.

CSystemClassFactroy {
    list runtimeClass;  
    RegisterClass(CRuntimeClass);
};  
application에서 사용할때는 아래와 같이 register를 해야 되는 상황이 있었습니다. 

main() {    
  // application 초기화    
  Factroy.RegisterClass(MyTestControl);  
  :
  :
}

이때 문득 MFC에서는 어떻게 하지? 라는 생각이 들어 이 RuntimeClass를 살펴본바... m_pNextClass 를 이용해서 각 register시에 RuntimeClass들을 줄줄이 사탕으로 엮어놓은 것이라 추측 할수 있었다.!!! 아하.!! 요렇게 하면 runtime class를 managing 하는 manager class가 필요 없겠구나.!! 하는 필(feel)을 받고, 제 코드도 요렇게 바꿨답니다. ㅎㅎ 

 
------------------------------------------------------------------------------------------------------------------------
 

 

잘 동작 않는다는 의견이 있어서 한번 짤막한 코드를 작성해봤습니다.
[셈플 코드]
rt_class.h
#ifndef __RT_CLASS_H__
#define __RT_CLASS_H__

#include <string>
#include <functional>
class Object
{
public:
 Object() = default;
 virtual ~Object() = default;
 virtual void test(){};
};


class RtClass {
public:
 explicit RtClass(std::string name, std::function<Object*(void)> func);
 virtual ~RtClass();
 std::string className;
 std::function<Object*(void)> createObject;
 RtClass* nextClass{nullptr};

 static Object* CreateObject(std::string className);
};


#define RT_CLASS(class_name) ((RtClass*)(&class_name::class##class_name)) 

#define DECL_RT_CLASS(class_name) \
 public: \
 static const RtClass class##class_name; \
 virtual RtClass* GetRuntimeClass() const;

#define IMPL_RT_CLASS(class_name) \
 const RtClass class_name::class##class_name(#class_name, [](void)->Object*{return (Object*)new(std::nothrow) class_name; }); \
 RtClass* class_name::GetRuntimeClass() const \
 { return RT_CLASS(class_name); }


#endif //__RT_CLASS_H__
 
 
 
 
rt_class.cpp

  

 
#include "rt_class.h"
 
static RtClass* pHead = nullptr;
 
Object* 
RtClass::CreateObject(std::string className)
{
  for (auto it = pHead; it != nullptr; it = it->nextClass){
    if (it->className.compare(className) == 0){
     return it->createObject();
    }
  }
 return nullptr;
}
 
RtClass::RtClass(std::string name, std::function<Object*(void)> func)
: className(name)
, createObject(func) {

  if (pHead == nullptr){
    pHead = this;
  }
  else{
    this->nextClass = pHead;
    pHead = this;
  }
}
 
RtClass::~RtClass()
{
 if (this == pHead){
   pHead = pHead->nextClass;
 }
 else{
   for (auto prev = pHead, it = pHead->nextClass; it != nullptr; it = it->nextClass){
     if (it == this){
       prev->nextClass = this->nextClass;
       return;
     }
     prev = it;
   }
 }
}

 

 
 
rt_sample.cpp
 
#include <stdio.h>
#include "rt_class.h"
 
 
class A: public Object{
 DECL_RT_CLASS(A);
 
 virtual void test(){
 printf("I'm A\n");
 };
};
 
 
 
class B: public Object{
 DECL_RT_CLASS(B);
 
 virtual void test(){
 printf("I'm B\n");
 };
};
 
 
IMPL_RT_CLASS(A)
IMPL_RT_CLASS(B)
 
 
 
 
test_main.cpp

 

#include "rt_class.h"


int main(){
 Object* pA = RtClass::CreateObject("A");

 pA->test();


 Object* pB = RtClass::CreateObject("B");
 pB->test();
 return 0;
}

 

 

구조를 잠깐 설명하자면,
1. rt_class 는 platform에 해당 합니다.
2. rt_sample.cpp 는 개발자 본인이나 다른 개발자가 개발하여 platform에 등록(추가) 되는 모듈입니다. ( 이부분이 update가 되는 부분)
  ( lib이나 dll 등으로 가져와서 사용한다고 생각하면 됩니다.)
3. test_main.cpp 는 어플리케이션입니다. 
 
이런 의도로 작성되었고, 실제로 rt_class.so, rt_sample.so, test_main 으로 나눠서 작업해봐도 동작할것입니다.
 
해당 application은 A와 B가 어딘가에서 제공된다는것을 알고 있지만 class는 모릅니다.
"A" 와 "B" 라는 이름(string)으로 클래스를 생성 하여 테스트 하는 코드입니다.
 
test_main은 실제 A와 B를 모르기 때문에, Object라는 상위 class가 제공하는 기능밖에 사용 할 수 없습니다.
test()라는 함수죠.!
그래서 이 방식으로 리플렉션(refection)을 완전히 대처하기는 힘듭니다.
 
Object에 공통된 interface들을 만들고 사용하는데에는 용이합니다. ( 큰 오버해드 없이 간략하게 사용할 수 있는 구조입니다.)
 
 
결과는 : 
I'm A
I'm B
 
 
찾아보기 키워드!!! 

[SEAL Reflex] 
[LibReflection] 
[XCppRefl 라이브러리]

 
<참고 링크>
[MSDN : C++ 리플렉션 in Visual C++ ]http://msdn.microsoft.com/ko-kr/library/y0114hz2(VS.90).aspx



 

 

 

 

반응형

소프트웨어 개발 업을 하다보니,  주변에서 좀 경험이 있든 없든 간에 많은 개발자분들로부터 "S/W는 재사용하기 힘들다" 이 말을 정말 많이 듣는 것 같습니다.

왜 S/W는 재사용이 어려울까? 이런 저런 생각들을 하다보니 S/W 공학과 재사용이라는 용어와 그 내용에 대해서 다시한번 고민해보게 되었습니다.
흔히들 공학이라고 불리는 하드웨어적인 부분들은, 아날로그적인 부분들을 수학적 접근에 의해 원리와 개념을 설명하는 것입니다.

또 내구도등 기타 여러가지 요인에 의해  매번 측정마다 약간씩의 오차가 발생하게 됩니다.그래서 이런 오차를 줄이고, 정확한 측정을 위한 알고리즘을 찾고 적용하고 보정하는 것에 대한 것입니다. 

그런데, 이런 관점에서 생각해보면 S/W 는 사실  공학적 접근이 필요하다고 말에 어폐가 있어보입니다.

S/W는 1+1=2 가 오차 없이 항상 나오고 CD를 백만번 카피해도 CD의 물리적인 오류가 없는한은 똑같은 DATA를 백만번 카피 할수 있습니다.
전자공학이나 생명공학 기계공학에서는 있을 수 없는 일입니다.

S/W는 기대한 만큼 완벽하게 결과를 내 놓기 때문에 측정이나 측정기의 검증등이 필요 없을 수 밖에 없습니다.

즉, S/W는 Code로 이뤄져있고 Digital Data로 만들어지며 , 오차가 존재하지 않기 때문입니다.


이러한 특성을 보면, 공학 보다는 수학에 가깝게 느껴집니다.

불변의 진리, 논리적 완벽성, 무한, 항상성(같은 결과) 등등 의 특성들을 보면 말이죠.

그리고 실제로 수학적 증명에서 부터 시작한것이구요.

 

이렇게 따져 보면 어떤 다른 분야보다도 S/W는 제 사용성이 높은 것이 맞습니다.

카피 해서 사용하면 되는 것이니까요.

 

그러면 왜 ? 유독 코드의 재사용성에 대한 얘기가 많이 나올까요?

좀 큰 S/W를 개발하다보면 항상 나오는 이야기인데 "S/W 재사용" 얘기를 빼 놓을 수 없습니다.

종종 H/W 부품들과 빗대어 표현할때도 있는데요.

"H/W는 블럭을 잘 디자인하고 표준화 해서 잘 쓰고 있는데 왜? S/W는 그렇게 못하냐"

"부품 처럼 갈아 끼울수 있으면 좋을텐데" 이런식의 표현이죠.

참 이상하죠.. Code는 수학과 비슷해서 한번 완성이 되고 나면 항상 같은 결과를 내기 때문에 불량도 없고, 고칠 필요도 없는데 말이죠.

과연 무엇과 비교해서 재 사용성이 낮은 것일까요?


으흐흐.. 대부분 사람들이 이렇게 얘기하죠..
"하면 좋죠... 근데 S/W는 그렇게 하기 어렵습니다." 요렇게 대답하죠... 

 


왜 S/W는 어려울까요?

H/W와 S/W의 가장 큰 차이부터 얘기를 해야 합니다.
H/W는 물질적인 것이고 S/W는 논리적인 것입니다.

물질 적인것은 분명 크기나 무게 등 물리적인 한계가 있습니다.  또 하나를 만들어 내기 위해서는 자원이 필요합니다.
또 자원을 조립하는 기계가 필요합니다. 또 대량 생산을 위해서는 공장이 필요합니다.
이렇기 때문에 이 비용을 최소화 하기 위해 표준화하는 것입니다. 만약 표준화가 안되면 대량 생산이 안되겠죠...
이렇게 표준화된 부품들 때문에 제조회사들에서 덕을 좀 보긴 합니다.
핸드폰에서 사용하던 LCD칩을 가지고 D-TV를 만들때도 사용 하기도 하죠. 

(그렇지만 조금만 생각해보면, 표준화된 칩을 사용하더라도 검증과 테스트에 많은 비용이 들어가죠, 오차, 오류 등등)
근데 이걸 보고 S/W도 이렇게 하라는 것인데요.

이런 관점에서는 소프트웨어는 표준화가 필요 없다는 것입니다.
소프트웨어는 이미 완성되는 순간 대량생산이 가능합니다. 어떻게? copy 명령어로 파일들 주루룩 카피하면 땡인것이죠..
근데 무슨 표준화가 필요하고 규격화할 필요가 있냔 것이죠.. 넌센스죠.

 

그런데 왜 업계에서 소프트웨어 재사용성이 어렵다고 하는지 이해하기 위해서는 먼저 소프트웨어를 어떻게 재사용하기를 기대하는지 먼저 정의할 필요가 있어보입니다.

- 구구단 어플리케이션의 계산 모듈을 스프레드쉬트 개발할때 사용하고 싶다.

- 구구단 어플리케이션을 다른 OS에서 사용하고 싶다.

- 구구단 어플리케이션의 GUI를 다른 어플리케이션에서 사용하고 싶다.

 

S/W의 재사용성에 대한 정의도 명확히 할  필요도 있습니다.

 

S/W의 재 사용성은 H/W와는 관점이 완전 다른것입니다.

한번 설계된 Code를 수정없이 다른 S/W(application이나 platform 등등) 에서 사용할수 있는가에 대한 것입니다.

소스 코드나 binary data는 다른 library를 사용하거나 제컴파일해서 사용하는 등 , 이식 작업때 환경의 변화가 발생하기 마련입니다.
Windows에서 사용하던 code를 Linux에서 사용한다거나, CPU가 변경된다거나, H/W가 변경되는 상황들이 발생하는 것이죠. 


또, 하나의 어플리케이션 내에서 여러 모듈들이 공동으로 사용하는 것을 공통된(Common) 한 모듈로 개발하는 것이 이 S/W의 표준화 목적이 될 수 있습니다.

 

하지만, 여기에 가장 큰 문제는 S/W는 너무 유연한 나머지 항상 변화하고 발전합니다. 

아무리 잘 만들어진 모듈이라 할지라도 몇년 지나면 기술에 뒤쳐지고 기능에서 뒤쳐지게 됩니다. 

가만히 있으면 아무도 사용하지 않는 모듈이 되는거죠. 그래서 늘 발전시키고 현재 필요한 기능들을 추가하고 보강하고 또는 삭제 하죠.

 

이렇게 변화하는 소프트웨어를 재사용성이라는 틀로 고정시키기에는 무리가 있을 것입니다.

 

어려운일이죠. 틀에 고정시키면 경쟁력을 잃고 자유롭게 하면 재사용이 어렵고 말이죠.

하지만 저는 Code의 제사용이라는 부분에 대해서는 아직도 많은 시도를 해볼 여지가 있다고 생각합니다.

 

제가 생각하는 미래의 소프트웨어 개발

(2024년 추가)

 

코드 재사용

코드의 재사용은 이제 더이상 문제가 안될것입니다. 인터페이스와 목적만 잘 기술 하면 AI가 코드를 작성해주니까요.

코딩

더이상 개발자가 텍스트 에디터를 열어서 코딩하지 않을것입니다.

소프트웨어 구성 모듈들을 그리고 나면 코드가 생성될 것입니다.

전체 아키텍쳐를 그릴 수 있는 사람이 중요해 지겠죠.

이 아키텍쳐를 그리는 것 조차 AI와 대화하면서 이뤄질 것입니다.

 

바로 앞까지 왔습니다.

 

#해피코딩

+ Recent posts