[Refactoring] C언어로 짜여진 레거시 코드의 리팩토링 방법은 무엇이 있을까요?

1,697 views
Skip to first unread message

Steve Yoon

unread,
Apr 26, 2010, 8:20:09 AM4/26/10
to ab...@googlegroups.com
안녕하세요? 윤경록입니다.
저는 임베디드 시스템을 타겟으로 하는 소프트웨어 엔지니어 입니다.
임베디드 시스템에서 작업을 하려고 보니, 두 가지 이유에 의해서 객체지향 언어를 사용하지 않도록 권유되고 있는데요.
첫번째는 디바이스 벤더(갑)에서 바이너리 이미지의 footprint를 최소한으로 요구하기 때문이고, 두번째는 C++을 쓰자니 C++로 객체지향 프로그래밍을 거부감 없이 쓰기 위한 경험 축적까지 너무 오래 걸린다고 하는 이유(C++은 컴파일러 레벨에서 객체지향 프로그래밍을 강제하지 않기 때문에) 때문이었습니다.
이런 실정으로 시중에 리팩토링 관련 서적을 보고 적용하기가 조금 어려운데요. 해당 책들이 대부분 객체지향 언어를 대상으로 하기 때문이었습니다. (제가 모든 책을 훑어보진 않았습니다만...)
지금까지는 경험에 의해 나름대로의 원칙(원칙은 리팩토링 책에서 나오는 것과 같은 것 같습니다. DRY와 동작 가능하지만 단순한 코드)을 가지고 작업하는데, 이렇게 하려니 밤샘을 해서 어떤 모듈 전체를 새로 짜버리는 때가 많이 있었습니다. 밤샘을 하며 리팩토링을 하다 보니, 다시 중복된 코드가 많아지게 되는 악순환에 빠지게 되구요.
요즘은 이 원인을 제가 C언어만 하다 보니 보는 눈이 좁아져서 작게 잘라 리팩토링 하는 법이 눈에 안보이는 것 같다는 생각이 들어서 난생 처음으로 자바 공부도 시작했습니다만 다른 방법이 없는지 궁금합니다.
관련된 책도 좋고, 구글링을 할 수 있는 키워드도 좋습니다.
도움을 주세요~

--
-----------------------------------------------------------------
Name : 윤경록
Mobile : +82-10-3008-7479
MSN : steve...@gmail.com
Nateon : steve...@nate.com
Blog : http://steveyoon77.tistory.com
me2DAY : http://me2day.net/steveyoon77
twitter : @steveyoon77
- 日新又日新 [일신우일신]

June Kim

unread,
Apr 26, 2010, 10:35:21 AM4/26/10
to ab...@googlegroups.com
C언어에서 리팩토링할 수 있는 기법들이 많습니다. 실제로 거의 한계가 없습니다. 저 스스로도 "이런 중복은 못 없애겠지" 싶은 것도 나중에 해법을 찾고나니 아주 간단하게 보였습니다.


리팩토링을 했는데 오히려 코드 중복이 많아진 경우나, (괴로운) 중복은 존재하는데 리팩토링하기 어려운 경우의 "(미니어처) 실제 코드"를 주시면 도움되는 답변을 드릴 수 있을 것 같습니다.


2010/4/26 Steve Yoon <steve...@gmail.com>
--
Google 그룹스 'Agile Beginners' Q&A' 그룹에 가입했으므로 본 메일이 전송되었습니다.
이 그룹에 게시하려면 ab...@googlegroups.com(으)로 이메일을 보내세요.
그룹에서 탈퇴하려면 abqna+un...@googlegroups.com로 이메일을 보내주세요.
더 많은 옵션을 보려면 http://groups.google.com/group/abqna?hl=ko에서 그룹을 방문하세요.

Steve Yoon

unread,
Apr 26, 2010, 9:34:16 PM4/26/10
to ab...@googlegroups.com
안녕하세요? 윤경록입니다.
처음 질문을 올릴 때 예제 코드를 함께 올리면 참 좋겠다는 생각은 했었습니다만, 막상 올리려고 보니 상용화 코드는 올릴 수 없고 그렇다고 질문을 위해 무엇인가를 새로 코딩해서 예제로 보일 정도로 실력이 좋지 못해서 못 올렸습니다. ^^;
그러다 문득 제가 신입 사원일 때의 기억을 떠올리게 되어서 해당되는 코드를 첨부할 수 있을 것 같습니다.

요구사항은 "FLUTE이라는 프로토콜의 client 단을 을 구현하되, 파일 시스템이 없는 타겟을 대상으로 외부 모듈에서 사용할 수 있는 인터페이스를 뽑아 라이브러리 형태로 구현하세요." 라는 것이었습니다.

당시에는 영어로 된 명세서(specification; ISO/IEC, ETSI, ANSI 등 단체에서 정의한 것이거나 RFC 등으로 정의된 것)에 대해서 읽어본 적도 없고, 명세서를 보고 코드를 구현할 정도로 경험이 있지 못해서 오픈 소스 코드를 배끼게 되었습니다.

만 5년만에 다시 "FLUTE"이라는 키워드로 구글링해서 겨우 그 때의 소스코드를 찾을 수 있게 되었는데요. (휴.. 겨우 찾았습니다.)

위의 페이지가 해당 오픈 소스 프로젝트의 홈입니다.
소스 코드를 다운로드 할 수 있는 http://mad.cs.tut.fi/index.php?content=download 페이지에서 코드를 다운로드 받아보면 "mad_fcl_v1.7_src\flutelib"의 경로에서 실제 FLUTE 프로토콜이 구현된 것을 찾을 수 있는데요.
이 중 flute.c을 리팩토링하여 클라이언트 단만 뜯어내고, 파일이 아닌 힙 메모리에 프로토콜로 전송된 실제 데이터를 저장하도록 고쳐야 했습니다.

처음에는 간단한 줄 알고 시작한 일이 3주일 가량 야근 또는 밤샘을 하고 나서 온통 전역 변수 플래그로 떡칠이 된 스파게티 코드로 바뀌게 된 것을 마음 깊이 깨닫게 되었습니다.
그래도 동작이 원활하게 잘되었고, 많은 시간 보고 또 보고 하여 익숙해진 탓에 결국 상용화까지 그대로 되어 버렸습니다. (다행히 이 때 까지 아무 문제도 생기지 않았습니다.)
이후 3년 뒤 그 프로젝트를 업데이트 하는 팀에서 이 부분의 코드를 새로 처음부터 짜게 되었고, 옆에서 도와주지도 않고 (그 땐 왜 그리 속이 좁았는지..) 여유있게 작업해서 부럽구나 라고만 했었습니다.

고쳐야 할 함수는 flute_receiver_report 로 기억되며 스레드는 사용하면 안되었습니다.
안타깝게도 당시 제가 리팩토링해서 상용화 한 코드는 가지고 있지 않습니다. 솔직히 다시 보고 싶지 않은 코드였습니다.

이 코드를 제가 지금 다시 리팩토링 하며 그 과정을 물어보는 것도 좋은 방법일 것 같은데, 일단은 원본 코드를 공유하는 것을 먼저 하고 주말에 그런 방식으로 다시 질문 해봐야 할 것 같습니다. (이번 주말에 지방에 내려갈 일이 있어서 혹시 그렇게 질문을 못하게 되면 다음주에라도 하겠습니다.)

그럼 이만 줄이겠습니다. 감사합니다.

윤경록 드림
flute.c

June Kim

unread,
Apr 26, 2010, 9:57:04 PM4/26/10
to ab...@googlegroups.com
안녕하세요. 우선 시간을 들여서 실제 코드를 찾아주셔서 감사합니다.

그런데 제가 한 가지 제안을 해도 될까요?

언급하신 함수는 800라인이 넘는 것 같습니다. 윤경록님께서 원하시는 핵심은 C언어에서 리팩토링을 어떻게 잘 하느냐라는 생각이 드는데, 좀 더 간단한 함수 하나(100라인 이하?)를 골라서 리팩토링 해보시고, 그것과 저나 다른 분들이 리팩토링한 것을 비교해보는 식으로 하시면 어떨까요?

1000라인이 넘는 C 함수를 리팩토링 한 적이 많이 있습니다만, 그런 함수로 이야기를 진행하자면 질문하시는 분이나 답하는 사람이나, 읽는 사람이나 시간 투자가 너무 많을 것 같아서요.

기본적인 전략은 긴 코드일수록 초기에 "Extract a Function"을 여러번 해서 몇 개의 덩어리들로 조각을 냅니다. 특히 중간에 주석으로 섹션에 중간 제목을 달아놓은 부분을 함수로 뽑습니다 -- 이때 함수 이름은 주석을 축약해서 하기도 합니다.

이걸 몇 번 하면서 짧게 잘라낸 함수 내부에서 다시 리팩토링을 진행합니다.

그리고 코드 기능 수정은 리팩토링 중에 하지 않습니다. 코드가 가독성이 높아지고 중복이 줄어들고 복잡도가 낮아져서 "아! 쉬운 코드군!"하는 느낌이 팍 들 때, 그 때 기능 수정(파일 시스템을 쓰지 않고, 스레드 쓰지 않게 바꾸기)을 합니다.


2010/4/27 Steve Yoon <steve...@gmail.com>
Message has been deleted

Steve Yoon

unread,
Apr 29, 2010, 11:40:36 AM4/29/10
to ab...@googlegroups.com
안녕하세요? 윤경록입니다.
회사가 멀어지니까, 보통 수준의 야근을 하고 왔는데도 이제야 집에 들어왔네요. 하지만 통근 시간이 한 시간 반이 조금 넘게 되어서 퇴근할 때는 지하철에서 책을 볼 수 있어서 좋군요.

이 주제에 대한 예제 코드를 다음 주 주말까지 작성해서 올려보겠습니다. 이번 주말엔 막내 결혼식이 있어서 고향에 갑니다;

출퇴근 시간에 조금씩 제가 어려움을 느끼는 리팩토링 과제의 예를 생각해보니까, 예를 작성하는데 100라인이 안되어도 충분할지도 모르겠다는 감이 오기 시작했습니다.

대략 스케치만 하자면, 
 1. 스탑 워치 프로그램을 짜려고 하는데 
 2. 두 개의 스레드가 있고 (UI, Clock)
 3. 이 중 하나의 스레드 내에서 몇 개의 중의적인 이벤트를 처리하는 플래그들로 논리 연산하여 조건 처리를 하도록 하고 (버튼 1:시작, 카운트 시간은 가지만 보여지는 시간은 멈춤; 버튼2:종료 및 리셋)
 4. 이 플래그가 전역변수인데 다른 스레드에서 값을 변경하도록 할 작정입니다. (UI 스레드에서 조작)

혹시 이 글타레가 시간에 묻혀 잊혀지거나, 겨우 떠올린 예제 프로그램의 스케치를 잊어버릴까봐 글을 남깁니다. ^^;

전에는 매일 쓸데없는 조바심이 나서 괜한 자학과 투정만 한 듯 합니다. 최근에 퇴계 이황 선생님의 글을 모아 쓴  신창호 님의 "함양과 체찰"을 읽고 느낀 점이 있어서 소 걸음 걷듯 살기로 하였습니다. 벼 이삭을 잡아 뽑는다고 벼가 빨리 자라지는 않는다는 말씀이 있었습니다. ^^

허접한 질문 하나를 하는데 몇 주가 지나가지만, 그게 밉다고 버려두지는 말아주세요. ^^;

Steve Yoon

unread,
May 9, 2010, 6:53:59 AM5/9/10
to ab...@googlegroups.com
안녕하세요? 윤경록입니다.

이제서야 질문을 위한 예제 코드를 올리게 되었습니다.
집에서 쓰는 PC에 우분투 OS만 깔려 있어서 리눅스 기반으로 작성하였습니다.
pthread 라이브러리를 링크 할 수 있어야 테스트 하실 수 있을 것 같습니다.

예제를 작성하고 보니 전형적인 C 프로그램의 형태로 잘 작성된 것 같습니다. 제 수준이 이것밖에 안됩니다; ㅠ.ㅠ

아래의 예고 글의 스케쥴과는 조금 다른 것 같은데, 변경된 내용은 이렇습니다
입력은 버튼 A, B, C입니다.
 A 버튼 : 스탑워치 시작, 히스토리 기록
 B 버튼 : 리셋
 C 버튼 : 프로그램 종료

예제 코드에서 지금 당장은 (제가 보기에) 아직 냄새가 심하게 나는 부분은 없어 보입니다.
그런데 만약 A 버튼이 "시작"의 의미로 한 번 눌린 뒤 2초 이내에 한 번 더 눌렸을 경우에 "히스토리 기록이 아닌 램프를 켜라"라는 요구사항이 추가하게 될 경우 지저분한 코드로 금방 바뀔 것이라는 생각이 듭니다. 제 경험 상 이런 경우가 무척 많았거든요.

이것은 지금 생각하기에, 제가 짠 이 예제 코드에는 (지금은 알 수 없지만) 이미 지저분한 코드로 쉽게 변경될 수 있는 요소가 존재하는 것 같습니다.
그런데 어떤게 그런건지 잘 모르겠습니다.

객체지향의 맛을 느끼기 위해 자바 공부는 계속하겠지만, 첨부된 예제 코드에 "지저분한 코드로 쉽게 변경될 요소"가 무엇인지, 그리고 어떻게 이러한 것들을 리팩토링 할 수 있을지 알고 싶습니다.

많이 도와주세요. 부탁드립니다.

그럼 이만 줄입니다.

윤경록 드림

2010년 4월 30일 오전 12:40, Steve Yoon <steve...@gmail.com>님의 말:

안녕하세요? 윤경록입니다.
회사가 멀어지니까, 보통 수준의 야근을 하고 왔는데도 이제야 집에 들어왔네요. 하지만 통근 시간이 한 시간 반이 조금 넘게 되어서 퇴근할 때는 지하철에서 책을 볼 수 있어서 좋군요.

이 주제에 대한 예제 코드를 다음 주 주말까지 작성해서 올려보겠습니다. 이번 주말엔 막내 결혼식이 있어서 고향에 갑니다;

출퇴근 시간에 조금씩 제가 어려움을 느끼는 리팩토링 과제의 예를 생각해보니까, 예를 작성하는데 100라인이 안되어도 충분할지도 모르겠다는 감이 오기 시작했습니다.

대략 스케치만 하자면, 
 1. 스탑 워치 프로그램을 짜려고 하는데 
 2. 두 개의 스레드가 있고 (UI, Clock)
 3. 이 중 하나의 스레드 내에서 몇 개의 중의적인 이벤트를 처리하는 플래그들로 논리 연산하여 조건 처리를 하도록 하고 (버튼 1:시작, 카운트 시간은 가지만 보여지는 시간은 멈춤; 버튼2:종료 및 리셋)
 4. 이 플래그가 전역변수인데 다른 스레드에서 값을 변경하도록 할 작정입니다. (UI 스레드에서 조작)

혹시 이 글타레가 시간에 묻혀 잊혀지거나, 겨우 떠올린 예제 프로그램의 스케치를 잊어버릴까봐 글을 남깁니다. ^^;

전에는 매일 쓸데없는 조바심이 나서 괜한 자학과 투정만 한 듯 합니다. 최근에 퇴계 이황 선생님의 글을 모아 쓴  신창호 님의 "함양과 체찰"을 읽고 느낀 점이 있어서 소 걸음 걷듯 살기로 하였습니다. 벼 이삭을 잡아 뽑는다고 벼가 빨리 자라지는 않는다는 말씀이 있었습니다. ^^

허접한 질문 하나를 하는데 몇 주가 지나가지만, 그게 밉다고 버려두지는 말아주세요. ^^;

윤경록 드림



--
-----------------------------------------------------------------
Name : 윤경록
Mobile : +82-10-3008-7479
MSN : steve...@gmail.com
Nateon : steve...@nate.com
Blog : http://steveyoon77.tistory.com
twitter : @steveyoon77
- 日新又日新 [일신우일신]
StopWatch.c

June Kim

unread,
May 10, 2010, 1:43:45 PM5/10/10
to ab...@googlegroups.com
2010/5/9 Steve Yoon <steve...@gmail.com>
안녕하세요? 윤경록입니다.

안녕하세요.
 

이제서야 질문을 위한 예제 코드를 올리게 되었습니다.

예제 만드신다고 수고가 많으셨습니다. 혹시 예제를 만드시는 과정 중에 교훈이 있었다면 어떤 것이 있으셨는지 궁금합니다.

그리고 예제 중에,

pthread_join(clock_thread, (void**)&thread_state);

부분은

pthread_join(clock_thread_handle, (void**)&thread_state);

로 바꾸는 것이 맞을 것 같습니다.

 
집에서 쓰는 PC에 우분투 OS만 깔려 있어서 리눅스 기반으로 작성하였습니다.
pthread 라이브러리를 링크 할 수 있어야 테스트 하실 수 있을 것 같습니다.

예제를 작성하고 보니 전형적인 C 프로그램의 형태로 잘 작성된 것 같습니다. 제 수준이 이것밖에 안됩니다; ㅠ.ㅠ


잘 작성하신 것 같은데 너무 겸손하신 것 아니세요? ^^;

아래의 예고 글의 스케쥴과는 조금 다른 것 같은데, 변경된 내용은 이렇습니다
입력은 버튼 A, B, C입니다.
 A 버튼 : 스탑워치 시작, 히스토리 기록
 B 버튼 : 리셋
 C 버튼 : 프로그램 종료

예제 코드에서 지금 당장은 (제가 보기에) 아직 냄새가 심하게 나는 부분은 없어 보입니다.

C 언어를 쓰기 때문에 냄새가 덜 나는 듯 보이는 부분이 있는 것 같습니다.

예를 들어, 아래의 clock_action 함수 내에서

void clock_action(void)
{
    switch(clock_state)
    {
        case CLOCK_START:
            count++;
            printf("TIME = %d sec\n", count);
            break;
        case CLOCK_CHECK:
            history = count;
            count++;
            printf("HISTORY = %d sec\n", history);
            clock_state = CLOCK_START;
            break;
        case CLOCK_RESET:
            count = 0;
            history = 0;
            break;
        case CLOCK_TERMINATE:
            pthread_exit(NULL);
    }
}


CLOCK_START와 CLOCK_CHECK 경우의 count++;이 중복인 것 같습니다. (두번이니 아직은 봐줄만 합니다만)

그리고, dispatch_command 내에서,

void dispatch_command(int command)
{
    switch(command)
    {
        case A_BUTTON_PRESSED:
            if(clock_state == CLOCK_START)
            {
                clock_state = CLOCK_CHECK;
            }
            else
            {
                clock_state = CLOCK_START;
            }
            break;
        case B_BUTTON_PRESSED:
            clock_state = CLOCK_RESET;
            break;
        case C_BUTTON_PRESSED:
            clock_state = CLOCK_TERMINATE;
        default:
            printf("there is no command\n");
            break;
        }
}

A_BUTTON_PRESSED 아래의 코드가 다른 케이스의 코드에 비해 무게가 더 나갑니다. 될 수 있으면 균형을 맞춰주는 것이 좋지 않나 싶습니다(예컨대 함수로 추출 등).  또 전체적으로 case 내부에 비슷한 패턴이 중복되어 보입니다. C_BUTTON_PRESSED 마지막에 break;를 추가하면 중복이 조금 더 잘 보일 겁니다.

그다음 dispatch_command와 clock_action이 모두 switch와 case를 구조로 하고 있다는 면에서 중복적인 면이 있습니다.

그리고 global이 많은 것 같습니다. 예컨대 dispatch_command 경우, 다음과 같이 리팩토링 하면 글로벌을 쓰지 않아도 됩니다:

int dispatch_command(int command,int clock_state) //returns next state

그리고 clock_action을 다음과 같이 리팩토링 합니다.

int clock_action(int clock_state) //returns next state

그런데 보시면 아시겠지만, CLOCK_CHECK에서만 state 변경을 하고 있습니다. 이런 경우 이 state 변경이 바깥에서 이루어지게 하거나 혹은 제거해서 clock_action 안에서는 아예 state 변경은 없게 만들면 불규칙성(irregularity)을 제거해서 중복을 늘리게 되고, 따라서 리팩토링하기가 쉬워집니다.

count나 history도 글로벌이 안되게 바꾸는 방법들이 있는지 한 번 고민해 보시면 좋을 것 같습니다.


(그런데 이런 잠재적 중복을 모두 고쳐야 제대로 리팩토링하는 거다, 혹은 더 좋은 코드다 라는 이야기는 아닙니다)


그런데 만약 A 버튼이 "시작"의 의미로 한 번 눌린 뒤 2초 이내에 한 번 더 눌렸을 경우에 "히스토리 기록이 아닌 램프를 켜라"라는 요구사항이 추가하게 될 경우 지저분한 코드로 금방 바뀔 것이라는 생각이 듭니다. 제 경험 상 이런 경우가 무척 많았거든요.

이것은 지금 생각하기에, 제가 짠 이 예제 코드에는 (지금은 알 수 없지만) 이미 지저분한 코드로 쉽게 변경될 수 있는 요소가 존재하는 것 같습니다.
그런데 어떤게 그런건지 잘 모르겠습니다.


리팩토링을 학습 과정이라고 생각하시면 좀 더 마음이 편해지실 것 같습니다. 지금 중복이 잘 안보이면, 일단 현 상태에서 기능 추가/변경을 해봅니다. 그러면서 고통스러운 부분이 나오면 일단 돌아가게 만들고(혹은 추가/수정할 기능을 더 단순화한 후 돌아가게 하고), 중복을 찾아 리팩토링합니다. 그러면서 한 수 배우는 겁니다. 아, 이런 부분들은 고통스러울 수 있구나. 앞으로는 이렇게 해야지.

그런데 리팩토링을 하면서 이런 실패의 순간을 맛보지 않으면 학습도 없는 겁니다. 실패를 무서워하면 두 가지 선택이 있습니다.

1) 최대한 리팩토링한 다음, 리팩토링 조금 더 한다. (즉 과도한 리팩토링)
2) 아예 하지 않는다.

둘 다 학습에 그렇게 좋은 영향을 주지 않습니다. 1번 경우는 괜히 불필요한 복잡성을 가져오게 되는 경향이 있습니다. 원래 풀어야할 문제에서는 주어지지 않았던 불필요한 개념들을 집어 넣습니다. 그러다보면 조금 해보고 실험해보고 하는 반복 주기가 길어지고, 피드백도 잘 못받게 되는 경우가 많습니다. 두 번 째는 그냥 현실을 받아들이며(사실은 눈감고 귀막고) 살기로 하는 방법입니다. 학습하지 못하죠.

리팩토링 할 것이 안보이면 그냥 갑니다. 간단한 기능 하나 추가해 보면서 느끼는 겁니다. 고통스럽다 싶으면, 이렇게 생각하면 됩니다. "오늘 또 한 수 배우겠구나"하고 편안하게 생각하시면 됩니다. 중요한 것은 실패한 다음 리팩토링 해보는 겁니다. (시간이 된다면 몇 번 더 해보는 것도 좋습니다)


객체지향의 맛을 느끼기 위해 자바 공부는 계속하겠지만, 첨부된 예제 코드에 "지저분한 코드로 쉽게 변경될 요소"가 무엇인지, 그리고 어떻게 이러한 것들을 리팩토링 할 수 있을지 알고 싶습니다.


한 번 "2초 내에 A 버튼을 다시 누르면 램프 키기" 요구사항을 추가해 보시고 리팩토링을 해본 다음 실험 결과를 알려주세요.

마음을 편하게 가지신다면 잘 하실 수 있으리라 믿습니다.

Steve Yoon

unread,
May 10, 2010, 9:14:12 PM5/10/10
to ab...@googlegroups.com
안녕하세요? 윤경록입니다.

답변 감사합니다. 정말 많은 도움이 되었습니다.

첫번째 예제 코드를 작성할 때의 제 소견과 김창준님의 답변으로부터 얻은 깨달음(?), 그리고 요구사항 추가로 인해 변경되는 코드는 2주 후(이번 주말에 또 결혼식 때문에 지방에 갑니다)까지 이 글타레에 이어서 올려보도록 하겠습니다. 제 깨달음(?)은 잠시 내용을 곱씹은 뒤에 올리는게 좋을 것 같아서 바로 이 글에 달지 않겠습니다.

왠지 과외를 받는 느낌입니다. 나중에 밥을 한 차례 살 수 있는 기회를 주시면 영광이겠습니다.

조금 더 욕심을 내서, C언어에서의 리팩토링에 대한 실천법(또는 패턴)도 만들어 낼 수 있으면 참 좋을 것 같습니다.

그럼 이만 줄이겠습니다.

윤경록 드림

2010년 5월 11일 오전 2:43, June Kim <june...@gmail.com>님의 말:

Ronie kang

unread,
May 13, 2010, 1:13:22 PM5/13/10
to ab...@googlegroups.com
안녕하세요! 강선영입니다.


윤경록님이 바쁘다는 말에 냉큼 만들어 보았습니다.^^
제가 리팩토링을 한 결과물을 첩부 합니다.


두개의 코드를 첨부 합니다.
1. StopWatch_Refactoring_roniekang.c
2. StopWatch_Requirements_roniekang.c


1번 소스는  원본 소스에 김창준님의 코멘트를 어느정도 반영하고,
기본 구조를 유지하며 심플함을 추구 하였습니다.

2번 소스는 윤경록님의 요구사항인 "A버튼이 2초 안에 눌리면 불이켜진다."라는
요구사항을 추가하였습니다.

이렇게 파일을 분리한 이유는 리팩토링한 부분과 요구사항이 반영된 코드를 한눈에 볼 수 있기 때문입니다.


간단한 원칙을 아래처럼 작성하고, 수정을 해보았습니다.

** 리팩토링
* 데이터 수준의 리팩토링
  1. 글로벌 변수들을 완전히 배제하지 못했지만 우선 struct로 묶었습니다.
  2. compilie 및 test로 이전과 동일한 결과확인
 
* 로직 수준의 리팩토링
   1. 중복 코드를 제거
   2.  Status를 심플하게 만들기 (Command 와 Action을 1:1 매칭 상태로 두고 싶었습니다.)
   3. compilie 및 test로 이전과 동일한 결과확인

* 기타
  1. 코멘트 정리 및 함수간의 공백추가
  2. 로직 블럭간의 공백 추가.

제가 코드 이해력과 눈높이가 낮다보니,
원본소스에서 크게 리팩토링을 할 부분이 보이지가 않았습니다.
정말 좀더 학습과 깨우침을 통해 혜안을 가졌으면 좋겠네요 ㅜㅜ;


** 요구사항 추가

요구사항을 추가하는 리팩토링이 된 이후에 기능이 추가가 되었습니다.
한번 정도 리팩토링이 된 이후이고 어렵지 않아 쉽게 끝났습니다 

하지만 처음 요구사항에 대한 기능을 추가할때 
제가 다르게 이해를해, 잘 못된 기능을 추가 하였습니다.

고객(윤경록님)의 요구사항은 "A 버튼이 "시작"의 의미로 한 번 눌린 뒤 2초 이내에 한 번 더 눌렸을 경우에 "히스토리 기록이 아닌 램프를 켜라" 이었는데

"저는 StopWatch가 최초 실행이 되고 2초 안에 A버튼이 눌렸을때 불이 켜진다"로 이해 하고
기능을 구현했습니다.

두리뭉실한 요구사항에 대해서는 고객과 충분히 대화를 하고, 
요구사항을 명확하게 도출하고, 내용을 문서로 만들어 상호 확인 및 검증하는 
절차가 필요한 것 같습니다.
 
정확한 요구사항은
"StopWatch가 실행이 되고, A버튼을 누르고  2초 뒤에  A버튼을 다시 누르면  화면에 불이 켜지는 기능 "
기능이었습니다.
---------------

** 요구사항 추가 
"A버튼을 눌러  History를 10개 까지 내부에 저장하고 있다가 
B버튼(Reset)이 눌리면 보여주는 기능을 추가 해주세요"
"만약 10개가 넘어간다면 가장 처음에 저장된 순서부터 삭제합니다."


** 제안
리팩토링을 진행하면서 변경사항들을 저장소 같은곳에 넣고 다 같이 볼수 있었으면
좋겠습니다. 
(저는 최근 GIT를 이용해 소스를  로컬에서 관리하고 있습니다.)


마치며....
저같은 초심자가 글을 쓰기에 딱 좋은 Agile Beginners가 있어서 기쁩니다.
용기를 100배 가지고 리팩토링에 참여하고 의견을 지속적으로 내고, 학습해 나가보도록 하겠습니다.
 

교훈 및 느낀점 :
1. 글쓰는 연습이 부족해서 코드 수정하는 것 보다 내용을 적는게 더 오래 걸렸습니다.
    작은 글이라도 자주 써보는 연습을 해야겠습니다.

2. 고객의 요구사항을 잘 이해하도록,
    대화화 문서를 만들고 서로 확인하는 과정이 필요함을 깨달았습니다.


다른분이 좀더 개선 시켜주셔요 !!

그럼 고운하루 되세요.
강선영 드림.

2010년 5월 11일 오전 10:14, Steve Yoon <steve...@gmail.com>님의 말:
StopWatch_refactoring_roniekang.c
StopWatch_Requirements_roniekang.c

Steve Yoon

unread,
May 13, 2010, 9:20:57 PM5/13/10
to ab...@googlegroups.com
안녕하세요? 윤경록입니다.
강선영군은 제가 개인적으로 알고 지내는 분이고, 이 작업은 제가 부탁을 했었습니다.
C로 짜여진 레거시 코드에 대한 리팩토링 방법에 대한 질문에 걸맞게 서로 다른 사람이 계속 리팩토링하여 레거시 코드를 유지하고자 하였습니다.
혹시 강선영군의 글타레가 생뚱맞다고 생각하실 분이 계실까봐 이렇게 사족을 답니다;
그럼 이만 줄이겠습니다.

윤경록 드림

2010년 5월 14일 오전 2:13, Ronie kang <ronie...@gmail.com>님의 말:

Hans Yoon

unread,
May 26, 2010, 11:48:25 PM5/26/10
to ab...@googlegroups.com
어제 정기모임에서 얘기했던 것 코드로 작성했습니다.
코딩룰이 약간 달라서 혼동스러운 부분이 있을 것이라고 보여지긴 합니다. (2 space indentation).

첨부한 소스의 기본적으로 다음의 함수 구조를 생각해서 정의한 것입니다.

pthread_mutex_init
pthread_mutex_destrocy
pthread_mutex_lock
pthread_mutex_unlock

이 함수들은 공히 맨 처음 파라미터로 pthread_t를 가지고 넘깁니다. 이 pthread_t가 실지로 어떻게 생겨먹었는지는 어떤 유닉스 계열의 OS도 정확하게 그 내용을 보여주지 않습니다. 그냥 쓰도록 합니다.

이런 구조는
fopen
fclose
fwrite
fread
ftell
등의 구조에서도 볼 수 있는 방식입니다.

그래서 첨부한 소스의 주요 함수는 다음과 같이 재배치하였습니다.

static int     MyStopWatch_Init(MYSTOPWATCH *this);
static void    MyStopWatch_Fini(MYSTOPWATCH *this);
static Command MyStopWatch_GetMessage(MYSTOPWATCH *this);
static void    MyStopWatch_SetMessage(MYSTOPWATCH *this, Command msg);
static void    MyStopWatch_SetTimeOption(MYSTOPWATCH *this); // PRIVATE
static void    MyStopWatch_RunTimeOption(MYSTOPWATCH *this); // PRIVATE
static void    MyStopWatch_Dispatch(MYSTOPWATCH *this, Command command, Action *colckstate);

실지로 전역변수를 없앨 수 있는 유일한 방식은 포인터입니다. 즉, 구조체에 대한 포인터만이 그 유일한 해결책입니다. 사실 이 단계는 졸업을 하고, 쓰레드 안정성에 대한 고민이라든지, 각 데이터 타입 또는 객체 간의 정보 전달(routing)이 더 어렵고 중요한 문제일 듯 합니다.
일부러 각 함수의 첫번째 인자의 변수이름을 "this"로 지정하였습니다.

이렇게 하면 완벽하게 모든 전역변수를 없앨수 있습니다.

이 단계에서 다음단계로 넘어가는 것은 소스의 분리입니다.
소스를
1. main.c
2. stopwatch.c
3. stopwatch.h
로 분리하는 것이 가능해집니다.
main.c과 stopwatch.h만 보아도 동작의 원리가 파악이 되도록 구성이 되어야 합니다.

세번째 단계로 해야할 일은
stopwatch.c/h를 대상으로 단위테스트 코드를 작성하는 것이겠지요??

실지로 임베디드에서 객체를 전역에 선언을 해야 하는 경우라고 하더라도
위의 방식의 코딩을 하는 것이 각 단위의 분리, 안정성이 높아질 것으로 보입니다.

사실, OOP를 잘 모르는 사람들은 C++, Java에 와서 OOP라는 개념이 잡힌 줄 압니다.
그러나, OOP는 C에서도 가능했고, 대부분 고수들은 그렇게 프로그램을 짜 왔습니다.


2010-05-14 (금), 10:20 +0900, Steve Yoon:
mystopwatch_oop.c

듬뿍

unread,
May 26, 2010, 11:50:33 PM5/26/10
to Agile Beginners' Q&A
윽, 한글이 다 깨지는 이유는 모르겠네요. 난 UTF8인데...

pthread_mutex_init
pthread_mutex_destrocy
pthread_mutex_lock
pthread_mutex_unlock

On 5월27일, 오후12시48분, Hans Yoon <ddumbu...@gmail.com> wrote:
> ӿ ߴ ڵ ۼ ߽ ϴ .
> ڵ ణ ޶ ȥ κ ̶ մϴ . (2
> space indentation).
>
> ÷ ҽ ⺻ Լ ؼ Դϴ .
>
> pthread_mutex_init
> pthread_mutex_destrocy
> pthread_mutex_lock
> pthread_mutex_unlock
>
> Լ ó Ķ ͷ pthread_t ѱ ϴ .
> pthread_t  ܸԾ  н 迭 OS Ȯ
> ʽ ϴ . ׳ մϴ .
>
> ̷


> fopen
> fclose
> fwrite
> fread
> ftell

> ִ Դϴ .
>
> ׷ ÷ ҽ ֿ Լ ġ Ͽ ϴ .


>
> static int     MyStopWatch_Init(MYSTOPWATCH *this);
> static void    MyStopWatch_Fini(MYSTOPWATCH *this);
> static Command MyStopWatch_GetMessage(MYSTOPWATCH *this);
> static void    MyStopWatch_SetMessage(MYSTOPWATCH *this, Command msg);
> static void    MyStopWatch_SetTimeOption(MYSTOPWATCH *this); // PRIVATE
> static void    MyStopWatch_RunTimeOption(MYSTOPWATCH *this); // PRIVATE
> static void    MyStopWatch_Dispatch(MYSTOPWATCH *this, Command command,
> Action *colckstate);
>

> ִ Դϴ . , ü
> ͸ ذ å Դϴ . ܰ ϰ ,
> ̶ , Ÿ Ǵ ü
> (routing) ư ߿ մϴ .
> Ϻη Լ ù ° ̸ "this" Ͽ ϴ .
>
> ̷ ϸ Ϻ ϰ ټ ֽ ϴ .
>
> ܰ迡 ܰ Ѿ ҽ и Դϴ .
> ҽ


> 1. main.c
> 2. stopwatch.c
> 3. stopwatch.h

> и ϴ ϴ .
> main.c stopwatch.h Ƶ ľ ǵ Ǿ
> մϴ .
>
> ° ܰ ؾ
> stopwatch.c/h ׽ Ʈ ڵ带 ۼ ϴ ̰ ??
>
> Ӻ 忡 ü ؾ ϴ ϴ
> ڵ ϴ и ,
> ϴ .
>
> , OOP 𸣴 C++, Java ͼ OOP
> дϴ .
> ׷ , OOP C ߰ , κ ׷ α׷ ¥
> ϴ .
>
> 2010-05-14 ( ), 10:20 +0900, Steve Yoon:
>
>
>
> > ȳ ϼ ? Դϴ .
> > ˰ ̰ , ۾ Ź
> > ߾ ϴ .
> > C ¥ Ž ڵ忡 丵 ɸ°
> > ٸ 丵 Ͽ Ž ڵ带 ϰ Ͽ ϴ .
> > Ȥ Ÿ ׸´ٰ Ͻ DZ ̷
> > ϴ ;
> > ׷ ̸ ̰ڽ ϴ .
>
> > 帲
>
> > 2010 5 14 2:13, Ronie kang <ronie.k...@gmail.com> :
>
> >         ȳ ϼ ! Դϴ .
>
> >         ϴ ٻڴٴ ŭ ҽ ϴ .^^
> >         丵 ø մϴ .
>
> >         ΰ ڵ带 ÷ մϴ .
> >         1. StopWatch_Refactoring_roniekang.c
> >         2. StopWatch_Requirements_roniekang.c
>
> >         1 ҽ   ҽ â ش ڸ Ʈ ݿ ϰ ,
> >         ⺻ ϸ ߱ Ͽ ϴ .
>
> >         2 ҽ ϴ 䱸 "A ư 2 ȿ
> >         ."
> >         䱸 ߰ Ͽ ϴ .
>
> >         ̷ и 丵 κа 䱸 ݿ
> >         ڵ带 Ѵ ֱ Դϴ .
>
> >         Ģ Ʒ ó ۼ ϰ , غ ҽ ϴ .
>
> >         ** 丵
> >         * 丵
> >           1. ۷ι 켱 struct
> >         ϴ .
> >           2. compilie test Ȯ
>
> >         * 丵
> >            1. ߺ ڵ带
> >            2.  Status ϰ (Command Action 1:1 Ī
> >         · ΰ ; ϴ .)
> >            3. compilie test Ȯ
>
> >         * Ÿ
> >           1. ڸ Ʈ Լ ߰
> >           2. ? ߰ .
>
> >         ڵ ط° ̰ ٺ ,
> >         ҽ ũ 丵 κ ʾҽ ϴ .
> >         н ħ ڳ׿ ̤ ;
>
> >         ** 䱸 ߰
>
> >         䱸 ߰ ϴ 丵 Ŀ ߰ Ǿ
> >         ϴ .
> >         ѹ 丵 ̰ ʾ ϴ  
>
> >         ó 䱸 ׿ ߰ Ҷ  
> >         ٸ ظ , ߰ Ͽ ϴ .
>
> >         ?( ϴ ) 䱸 "A ư " " ǹ̷
> >         2 ̳ 쿡 " 丮 ƴ
> >         Ѷ " ̾ µ
>
> >         " StopWatch ǰ 2 ȿ A ư
> >         " ϰ
> >         ߽ ϴ .
>
> >         θ 䱸 ׿ ؼ ? ȭ ϰ ,  
> >         䱸 Ȯ ϰ ϰ , ȣ Ȯ
> >         ϴ  
> >         ʿ ϴ .
>
> >         Ȯ 䱸
> >         "StopWatch ǰ , A ư  2 ڿ  A ư
> >          ȭ 鿡 "
> >         ̾ ϴ .
> >         ---------------
>
> >         ** 䱸 ߰  
> >         "A ư  History 10 ο ϰ ִٰ  
> >         B ư(Reset) ִ ߰ ּ "
> >         " 10 Ѿ ٸ ó մ
> >         ."
>
> >         **
> >         丵 ϸ鼭
>
> ...
>
> 추가 정보 »
>
>  mystopwatch_oop.c
> 6K보기다운로드

Hanuri7421

unread,
May 27, 2010, 1:03:01 AM5/27/10
to ab...@googlegroups.com
음 팀내의 원할한 코드 공유를 위해서 팀간 코딩 스타일을 약속한다고 하던
데... 여기서 사용할 코딩 스타일을 간단한것들을 정하는건 어떤가요???

오픈소스 프로젝트들도 코딩규칙을 가지고 하지 않나요??

별로인가요??


Ronie kang

unread,
May 27, 2010, 2:58:40 AM5/27/10
to ab...@googlegroups.com
안녕하세요 강선영입니다.
 
우선 지금까지 변화된 코드를 SVN으로 볼수 있도록 gogole code에 옮겨두긴 했습니다.
 
google code에서는 코드 View는 별다른 제약이 없지만,
commit을 하기 위해서는 프로젝트 맴버에 추가가 되어야 합니다.(이점이 불편합니다.)
 
* 웹에서 제약없이 수정과 커밋을 할 수 있는 곳으로 옮겨 탔으면 합니다.
 
 
관련주소
https://code.google.com/p/agilekorea/
 
 
SVN 주소
http://agilekorea.googlecode.com/svn/trunk/
 
 
Web에서 Source보기
https://code.google.com/p/agilekorea/source/browse/
 
 
을 통해서 Tags 폴더에 리팩토링 해주신 분들에 소스를
살펴 볼수 있습니다.
(Trunk 폴더에는 가장 최근 소스가 들어 있습니다. )

 
이상 입니다.
강선영 드림..
 
2010년 5월 27일 오후 12:50, 듬뿍 <ddum...@gmail.com>님의 말:

Steve Yoon

unread,
May 27, 2010, 9:07:00 AM5/27/10
to ab...@googlegroups.com
안녕하세요? 윤경록입니다.

대단히 감사합니다!!!
어제 조언 주신대로 제가 작성해 볼까 했었는데, 먼저 올려주셨군요!

그런데 전역변수를 모두 없앨 필요가 있었을까 하는 생각이 듭니다.

예전에 기회가 있어서 OpenSSL에서 RSA 암호 모듈을 분리해내려는 시도를 해봤을 때의 기억이 떠올라서 이런 의문이 들었습니다.
OpenSSL의 RSA 모듈은 리팩토링 한 코드처럼 Context(리팩토링된 코드에서의 this를 임의로 명칭함) 전달하는 형식을 따르고 있었습니다. 어떤 부분은 매크로로 단순화 시킨 부분이 있어서 더욱 곤란했었죠. 물론 암호화 알고리즘에 대해서 거의 모르는 상태로 코드만 보고 분리를 하려 했었다는게 문제이기는 했습니다.

int RSA_public_encrypt(int flen, const unsigned char *from, unsigned char *to,
    RSA *rsa, int padding)
{
return(rsa->meth->rsa_pub_enc(flen, from, to, rsa, padding));
}

이런 기억 때문에 '어느 정도 수준에서의 코드 정리만 하자' 라는 생각이 들게 되었습니다. 그리고 지금은 '도대체 어느 정도 수준까지만 정리하면 되는가' 하는 고민 때문에 이런 글타레를 열어서 질문을 하게 된 것 입니다.

하지만, 리팩토링 하신 바와 같이 this로 넘겨주는건 정말 멋진 방법인 것 같습니다!

그런데 아직 이 예제 코드에서 더 우려 먹을게 남아있을 것 같은 생각이 들어서 다시 한 번 요구사항을 변경/추가하는 만행을 저질러 보려고 합니다. ^^;

우리가 만드는 스탑 워치가 운이 좋게도 end user에게 어필이 잘되어서 시장에 좋은 소문이 돌게 되었습니다. 그래서 새로운 고객이 생겼고, 이 고객은 버튼 수가 많다고 하나를 줄여달라고 합니다. 개발자들은 고민을 하다가 Long/Short event라는 개념을 생각해 내고 버튼을 두 개로 줄일 수 있게 되었습니다.
즉, A long/a short, B long/b short event로 해결하게 된 것 입니다.
 - A (long) : lamp
 - a (short) : toggle start/lap time
 - B (long) : power off
 - b (short) : reset

그런데 문제가 남아있었습니다. 기존의 고객사에게 2년간 유지보수를 해주는게 계약서에 명기되어 있었던 것 입니다.
그래서 코드는 고객사 A(기존 고객)와 고객사 B(신규 고객)에게 각각 배포되어야 했습니다.
이 상황에서 우리의 스탑워치 코드는 어떻게 변해가야 올바를까요?

이 요구사항이 추가된 코드는 이번 주말에 작성해서 올려보도록 노력하겠습니다. ^^;
미리 귀뜸을 드리자면, 저는 무쟈게 많이 봐온 '전형적인 C 스타일의 코드'로 #ifdef CLIENT_A #else #endif를 쓸 작정입니다.

애자일 커뮤니티의 많은 분들이 저와 함께 코딩 놀이를 즐겨주시면 감사하겠습니다.

그럼 이만 줄이겠습니다. 많이 많이 가르쳐주세요!

윤경록 드림


2010년 5월 27일 오후 12:48, Hans Yoon <ddum...@gmail.com>님의 말:

석한울

unread,
May 27, 2010, 9:18:00 AM5/27/10
to ab...@googlegroups.com

안녕하세요^^ 석한울 입니다.

 

음.. 전역변수를 모두 없엘 필요가 있을까? 라고 하셧는데.. 그냥 제가 해답을 제사한다기 보다는 저도. 그냥 생각을 해서 참여를 해볼까 합니다.

만약에.. 스탑워치가 하나만 필요한것이 아니라. 여러개의 스탑워치가 필요하게되었습니다. 시간을 제고 기록할 것이 많아진것이죠.

 

1. 사용자는 스탑워치를 사용해서 여러개의 시간을 젤수 있어야 한다.

 

2. 사용자는 현재 가지고 있는 모든 스탑워치의 진행 상태를 볼 수 있어야 한다.

 

라는 요구사항을 추가해 보면 어떨까요.. 전역변수가 여전히 아무런 문제도 일이키지 않을까요?

Steve Yoon

unread,
May 27, 2010, 12:06:09 PM5/27/10
to ab...@googlegroups.com
안녕하세요? 윤경록입니다.
메일을 보내자 마자 퇴근해서 집에 왔는데, 시각이 벌써 한 시네요. ㅠ.ㅠ
석한울님 감사합니다! 굉장히 좋은 요구사항이 생겼습니다!
이 요구사항도 반영하면서 리팩토링을 해나가면 참 재미있을 것 같습니다.
이 글을 읽으시는 다른 분들도 짬이 나시면 함께 참여해주세요. 
이곳에서 글을 보는 시간이 서로 가르치며 배우는 즐거운 시간이길 바랍니다!
지금 요구사항 추가와 리팩토링을 하고 싶지만, 내일 출근해서 졸지 않으려면 얼른 자야겠죠.
그럼 편안한 밤 되세요!

윤경록 드림 

2010년 5월 27일 오후 10:18, 석한울 <hanur...@naver.com>님의 말:

--
Google 그룹스 'Agile Beginners' Q&A' 그룹에 가입했으므로 본 메일이 전송되었습니다.
이 그룹에 게시하려면 ab...@googlegroups.com(으)로 이메일을 보내세요.
그룹에서 탈퇴하려면 abqna+un...@googlegroups.com로 이메일을 보내주세요.
더 많은 옵션을 보려면 http://groups.google.com/group/abqna?hl=ko에서 그룹을 방문하세요.

Lee, Jooyoung

unread,
May 27, 2010, 12:16:58 PM5/27/10
to Agile Beginners' Q&A
윗분글을 읽고 생각해보니 예전에 작업했던 퀄컴 BREW 플랫폼의 라이브러리가 비슷하게 작성된것이 기억나네요.
모든 라이브러리가 함수가 아닌 struct에 함수포인터를 멤버로 넣어 클래스처럼 동작하게 되었었죠.
나름 레퍼런스 카운터도 가지고 있더군요.
그때의 BREW라이브러리 코드를 찾아 조금 잘라봤습니다.
BREW에서 C만 된다고 누군가 그랬었는데 나중에 보니 아니였습니다.


// Header ///////////////////////////////////////////////////////////

#define VTBL(iname) iname##Vtbl

#define QINTERFACE(iname) \
struct _##iname {\
struct VTBL(iname) *pvt;\
};\
typedef struct VTBL(iname) VTBL(iname);\
struct VTBL(iname)

#define DECLARE_IBASE(iname) \
uint32 (*AddRef) (iname*);\
uint32 (*Release) (iname*);


QINTERFACE(IGraphics)
{
DECLARE_IBASE(IGraphics)

RGBVAL (*SetBackground)(IGraphics *po, uint8 r, uint8 g,
uint8 b);
void (*GetBackground)(IGraphics *po, uint8 *r, uint8
*g, uint8 *b);

RGBVAL (*SetColor)(IGraphics *po, uint8 r, uint8 g,
uint8 b, uint8 alpha);
void (*GetColor)(IGraphics *po, uint8 *r, uint8 *g,
uint8 *b, uint8 *alpha);

boolean (*SetFillMode)(IGraphics *po, boolean fFill);
boolean (*GetFillMode)(IGraphics *po);
...
...
};

#define IGRAPHICS_AddRef(p) GET_PVTBL(p,
IGraphics)->AddRef(p)
#define IGRAPHICS_Release(p) GET_PVTBL(p,
IGraphics)->Release(p)
#define IGRAPHICS_SetBackground(p, r, g, b) GET_PVTBL(p,
IGraphics)->SetBackground(p, r, g, b)
#define IGRAPHICS_SetColor(p, r, g, b, a) GET_PVTBL(p,
IGraphics)->SetColor(p, r, g, b, a)
#define IGRAPHICS_SetFillMode(p, m) GET_PVTBL(p,
IGraphics)->SetFillMode(p, m)
#define IGRAPHICS_GetBackground(p, r, g, b) GET_PVTBL(p,
IGraphics)->GetBackground(p, r, g, b)
#define IGRAPHICS_GetColor(p, r, g, b, a) GET_PVTBL(p,
IGraphics)->GetColor(p, r, g, b, a)
#define IGRAPHICS_GetFillMode(p) GET_PVTBL(p,
IGraphics)->GetFillMode(p)


// Impl ///////////////////////////////////////////////////////////

IGraphics *m_pGraph;

if(SUCCESS == ISHELL_CreateInstance(m_pShell, AEECLSID_GRAPHICS,
(void**)&m_pGraph))
{
IGRAPHICS_SetColor(m_pGraph, GetRValue(c), GetGValue(c),
GetBValue(c), 0);
....

IGRAPHICS_Release(m_pGraph);
}

///////////////////////////////////////////////////////////

멤버 함수포인터의 초기화는 CreateInstance시에 라이브러리에서 해줬던거 같습니다.
직접 구현한 코드들도 위처럼 했었는데 좀 코딩이 많았던것 같네요.

참고가 되셨으면 좋겠습니다.

> 2010년 5월 27일 오후 12:48, Hans Yoon <ddumbu...@gmail.com>님의 말:

> > 2010년 5월 14일 오전 2:13, Ronie kang <ronie.k...@gmail.com>님의 말:

> ...
>
> read more >>

Steve Yoon

unread,
May 27, 2010, 9:29:00 PM5/27/10
to ab...@googlegroups.com
안녕하세요? 윤경록입니다.
저도 BREW를 했었는데, 정말 오랜만에 다시 들어보는 것 같습니다. 그리운 분들이 떠오르기도 하네요. ^^
feature phone에서 아직 삼성이나 LG가 자체 UI SDK를 가지고 있지 않았을 때 BREW를 썼었던 것으로 기억되는데, 그 때 C 컴파일만 쓰도록 했던 것은 권장 사항이었던 것으로 기억합니다.
이유는 당시 (6년전) ARM 컴파일러에서 C++의 모든 요소를 지원하지 않았었기 때문이었던 것으로 기억되구요. 더 정직한 이유는 퀄컴의 baseband 코드가 C로 작성되어 있어서 베끼다 보니 그렇게 된 것으로 추측하고 있습니다.
하지만 4년 전 쯤에 C++로 작성된 코드도 보았고, C++로 작성된 쪽은 나름 기술적으로 자신감을 갖을 만하다고 생각된 부분(게임 솔루션)이었기에 '부서별 선택'이 있었던 것으로 추측합니다.
교통사고 때문에 30분 지각하여 출근했는데, 추억을 떠올리게 하는 글이 있어서 덧글을 달았습니다. 
혹시 잘못된 정보를 전달하고 있다면 정정 부탁드립니다. 감사합니다.

윤경록 드림

2010년 5월 28일 오전 1:16, Lee, Jooyoung <petab...@gmail.com>님의 말:
--
Google 그룹스 'Agile Beginners' Q&A' 그룹에 가입했으므로 본 메일이 전송되었습니다.
이 그룹에 게시하려면 ab...@googlegroups.com(으)로 이메일을 보내세요.
그룹에서 탈퇴하려면 abqna+un...@googlegroups.com로 이메일을 보내주세요.
더 많은 옵션을 보려면 http://groups.google.com/group/abqna?hl=ko에서 그룹을 방문하세요.

석한울

unread,
Jun 11, 2010, 8:42:39 PM6/11/10
to ab...@googlegroups.com

안녕하세요 이 쓰레드가 없어져 버리려고 하네요 호호

얼마전에 저도 이 쓰레드의 리펙토링을 시작하려고 해봤는데 허걱..

제가 리눅스나 쓰레드 프로그래밍 경험이 없어서.

애를 먹었습니다.

아예 동작하는 코드부터 시작한게 아니라서. 테스트를 어떻게 작성해야 할지도 모르겠고.

일단 Win32에서 돌아가게만 만들자라는 생각에  MSDN을 뒤져가면서.

 

Win32에서 동작하게 땜빵식으로 바꿔봤습니다.

그냥 Win32가 아니라서. 같이 리팩토링에 참여하고 싶은데 못하고 계시는 저같은 분이 또 있을까 해서요.

일단 이렇게 올리고 테스트코드도 추가해 보고

리팩토링도 해보고. 요구사항도 또 추가해 보는건 어떨까요^^

 

그리고 C++프로젝트로 바꿔보는거는요??

석한울

unread,
Jun 11, 2010, 9:00:39 PM6/11/10
to ab...@googlegroups.com

파일 첨부 합니다^^

RefactoringForStopWatch.zip
Reply all
Reply to author
Forward
0 new messages