자동화된 소스 분석, 처리, 검증을 통한 소스의 불필요한 #if - #endif...

Post on 28-Nov-2014

20.720 Views

Category:

Technology

4 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

TRANSCRIPT

자동화된 소스 분석, 처리, 검증을 통한 소스의 불필요한 #if - #endif 제거하기

김이선

veblush@[nexon|gmail]

BNB 프로그래머

카트라이더 리드 프로그래머

버블파이터 프로토타입

리드 프로그래머 에버플래닛

리드 프로그래머 던전엔파이터

테크니컬 디렉터 GTR

프로그래머

게임 프로그래밍 11년차

프로젝트 소스 코드의

유지보수성 (Maintainability) 관리가 중요!

[던전엔 파이터] 에서 했던

코드 관리 중 하나인

불필요한 #if - #endif 제거 작업

분석 처리 검증 결론 결과 도입 도입

오늘 알아볼 코드

[던전엔 파이터]

“퀘스트 시스템”

추가 작업

// 김철수: 퀘스트 시스템 구현

//#define _QUEST_SYSTEM

Flags.h

1단계

플래그 정의

#ifdef _QUEST_SYSTEM

ui.questWnd.setButton(…);

ui.questWnd.setEvent(…);

#else

ui.questWnd.setDisable();

#endif

*

2단계

기능 구현

// 김철수: 퀘스트 시스템 구현

#define _QUEST_SYSTEM

Flags.h

3단계

기능 플래그 켬

작업 중인 코드가

다른 작업자, 라이브 코드에

영향을 주지 않음

(장기간 작업, 빠른 롤백, 이벤트)

국가별 소스 코드 공유에 도움

(국가별 플래그, …)

간단한 작업 방식

(교육 비용이 낮음)

플래그 켬/끔이 Rebuild 를 초래

(Flags.h 파일을 모든 파일이 #include 하므로)

코드가 점차 읽기 어렵고 수정하기 어려워짐

(#ifdef - #endif 블록이 코드에 가득 차기 시작함)

코드가 점차 읽기 어렵고 수정하기 어려워짐

(#ifdef - #endif 블록이 코드에 가득 차기 시작함)

죽은 코드가 생겨남

(꺼진 플래그나 #else 에 묶엔 코드들)

그럼 플래그가 얼마나?

5400 개

+1500 /1yr

2015 년 10000 개

플래그 개수가 늘어남에 따라

발생하는 추가적인 문제!

#ifdef _EVENT_2006

ui.notice.setText(“월드컵 이벤트!”);

ui.notice.setVisible(1);

ui.notice.setEventHandler(…);

#endif

문제 1

죽은 코드

#ifdef _NEW_UI_COMPONENT

ui.notice.setText(“…”);

ui.notice.setVisible(1);

#else

set(UI_NOTICE, TEXT, “…”);

set(UI_NOTICE, VISIBLE, 1);

#endif

문제 2

중복 코드

플래그 작업 방식은 유지하되

불필요하게 늘어난 플래그 개수를 줄여보자

불필요한 플래그 제거!

ui.quest.setVisible(1);

ui.quest.setEventHandler(…);

플래그 켜서 제거

#ifdef _QUEST_SYSTEM

#endif

ui.quest.setVisible(1);

ui.quest.setEventHandler(…);

플래그 켜서 제거

#ifdef _EVENT_2006

ui.notice.setText(“월드컵 이벤트!”);

ui.notice.setVisible(1);

ui.notice.setEventHandler(…);

#endif

플래그 꺼서 제거

플래그 꺼서 제거

#define _NEW_QUEST

플래그 병합

제거

#ifdef _NEW_QUEST

# define _NEW_QUEST_FIX

#endif

#ifdef _NEW_QUEST

ui.event.setText(…);

# ifdef _NEW_QUEST_FIX

ui.event.setPos(…);

# endif

#endif

#define _NEW_QUEST

플래그 병합

제거 #ifdef _NEW_QUEST

ui.event.setText(…);

ui.event.setPos(…);

#endif

개운하다!

제거할 플래그 선택

소스에서 플래그 제거

테스트

수천개를 수작업으로?

Image: http://www.flickr.com/photos/15271532@N00/1172675049

리팩토링 딜레마! 실수하면?

누가하지?

자동화

Image: http://www.enggtechsolutions.com/?page_id=5

제거할 플래그 선택

소스에서 플래그 제거

테스트

선택 자동화

제거 자동화

검증 자동화

분석 처리 검증 도입 결론 결과

플래그에 대한 정보 얻기 (삭제할 플래그를 추리기 위해)

소스 파일

#define F | #undef F

#ifdef F | #ifndef F | #if defined(F)

국가별 Flags.h 파일에 정의된 플래그 추리기

#define 뒤에 있는 주석도 가져오기

Subversion Log

모든 커밋의 Rev#, 날짜, 작성자, 로그

변경한 파일에 포함된 플래그 목록

플래그 정보 _QUEST_SYSTEM

사용: 한국, 중국

날짜: 2008-06-21

파일: Interface/QuestWindow.h

Interface/QuestWindow.cpp System/Quest.h

System/Quest.cpp

SVN: #29110, ironwater

“[추가] 퀘스트 시스템 1차 작업”

주석: 김철수, 퀘스트!

판단을 내릴 정보 가공! (단순한 정보 나열을 구체화)

플래그 정보 쿼리 결과

DB 테이블 쿼리 수행

DB 를 통해 유연한 분석 가능

국가별 / 연도별 플래그 등장 표

DB: 큰 그림 분석

시간별 증감 추이

국가별 사용 현황

작업자별 플래그 추가 파일별 플래그 추이

플래그 영향력

DB: 오류 분석

정의만 되고 사용되지 않음 (버려짐?)

정의는 없고 사용만 있음 (오타?)

정의가 여러 곳에 있음 (응?)

정의가 여러 곳에 있으면서 값이 다름 (으악!)

모두 켜거나 끈 플래그 목록 추리기

모든 국가에서 켜고 끈

플래그 수집

작성자 및 상급자에게 삭제 리뷰

요청

피드백을 받아 진행

분석 처리 검증 도입 결론 결과

제거할 플래그를

소스에서 제거

ui.quest.appendMsg(“…”);

questDlg.show();

플래그 켜서

제거

#define _QUEST_SYSTEM // 퀘스트

#ifdef _QUEST_SYSTEM

#endif

ui.quest.appendMsg(“…”);

questDlg.show();

플래그 켜서

제거

ui.event.setVisible(0);

플래그 꺼서

제거

#ifdef _EVENT_2008 // 2008 설 이벤트

ui.event.setText(…);

ui.event.show();

#else

#endif

ui.event.setVisible(0);

플래그 꺼서

제거

#define _NEW_QUEST

플래그 병합

제거

#ifdef _NEW_QUEST

# define _NEW_QUEST_FIX

#endif

#ifdef _NEW_QUEST

ui.event.setText(…);

# ifdef _NEW_QUEST_FIX

ui.event.setPos(…);

# endif

#endif

#define _NEW_QUEST

플래그 병합

제거 #ifdef _NEW_QUEST

ui.event.setText(…);

ui.event.setPos(…);

#endif

http://dotat.at/prog/unifdef

Unifdef 가 기본적인 기능은 잘 해줌

다만 부분 평가는 해주지 않음

#if defined(A) && defined(B)

A=켬|끔 B=그냥둠

#if 1|0 && defined(B)

병합 제거는 따로 구현

#ifdef A

# ifdef A_fix

# endif

#endif

#ifdef A

#endif

작업 흐름

unifdef 부분 평가 병합 제거

원시소스

제거 플래그 리스트

결과소스

분석 처리 검증 도입 결론 결과

처리 원시소스 결과소스

원시EXE 결과EXE =

동일한 소스를 두 번 빌드 후 EXE

빌드시간, 디버그 정보 등이 EXE 에 포함

동일한 소스를 두 번 빌드 후 OBJ

디버그 정보가 OBJ 에 포함

# name

#1 .drectve

#2 .debug$S

#3 .text

#4 .debug$S

#5 .rdata

#6 .text

#7 .debug$S

#8 .debug$T

OBJ 비교할 때

debug 섹션은 제외!

처리 원시소스 결과소스

원시OBJ 결과OBJ =

원시OBJ 결과OBJ ≠

DUMPBIN

처리 원시소스 비교 OK 같음

다름

다른 함수 찾기

원인 파악 툴 버그

소스 문제

플래그 켬/끔 오류

#include “show.h” //#include “Flags.h” void show() { #ifdef _QUEST_SYSTEM ui.quest.print(…); ui.questDlg.show(); #endif }

오류의 예

ASSERT 매크로 등에 있음!

검증 단계의 unifdef 는 행을 유지하도록.

__LINE__

__TIME__

작업 전에만 지웠다가 다시 살림.

분석 처리 검증 도입 결론 결과

제거 플래그 후보 선택

작업자의 리뷰

처리 / 검증 / 커밋

자동화 자동화

작업자 리뷰에 시간이 들기 때문에

리뷰 플래그 개수를 한번에 300~500 개로 유지

6 번의 플래그 제거 작업

총 2,107 개의 플래그 제거

2,309 파일에서

191,979 라인 제거

90%

10%

라인

코드 제거

작성한 툴

분석

처리

검증

Track

Uniform

CompareBin

소스 & SVN 에서 정보 수집

Unifdef + 추가 소스 처리

OBJ 파일 동일 검사

BatchRun 플래그 제거 및 검증을 일괄 실행

작성한 툴

분석

처리

검증

Track

Uniform

CompareBin

소스 & SVN 에서 정보 수집

Unifdef + 추가 소스 처리

OBJ 파일 동일 검사

BatchRun 플래그 제거 및 검증을 일괄 실행

총 LOC:

1500

분석 처리 검증 도입 결론 결과

불필요한 #if - #endif 제거는

소스 코드를 깔끔하게 유지하는데 도움!

소스의 유지보수성을 확보하는 작업을

자동화 시키고 신뢰성 있게 만드는 것이 중요!

자동화된 솔루션은 반복해서 사용할 수 있어

계속해서 도움을 받을 수 있음!

분석은 처리 뿐 아니라 대상을 바라보는

다른 관점을 제시하는 데에도 도움을 줌!

분석, 수행, 검증의 틀을

코드 / 데이터를 개선하는데 사용해보자!

문제되는 이름 추리기

소스에서 자동 변경

빌드 테스트

자동화된 Rename 리팩토링 ?

여러분들도!

감사합니다!

top related