<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko">

	<title type="text">KAISTIZEN</title>
	<subtitle type="text"></subtitle>
	<link rel="alternate" type="text/html" href="http://kaistizen.net/EE/index.php/weblog/index/" />
	<link rel="self" type="application/atom+xml" href="http://kaistizen.net/EE/index.php/weblog/rss_atom/" />
	<updated>2008-11-27T16:05:50Z</updated>
	<rights>Copyright (c) 2008, 최재훈, http://creativecommons.org/licenses/by-nc-sa/2.0/kr/</rights>
	<generator uri="http://www.pmachine.com/" version="1.6.3">ExpressionEngine</generator>
	<id>tag:kaistizen.net,2008:11:26</id>


	<entry>
		<title>실전! 지속적인 통합 10편: MSBuild 따라하기</title>
				<link rel="alternate" type="text/html" href="http://kaistizen.net/EE/index.php/imaso/continuousintegration_2008_10/" />
				
		<id>tag:kaistizen.net,2008:EE/index.php/weblog/index/2.1443</id>
		<published>2008-11-29T17:39:00Z</published>
		<updated>2008-11-29T17:58:24Z</updated>
		<author>
			<name>최재훈</name>
			<email>kaistizen@gmail.com</email>
			<uri>http://kaistizen.net</uri>		</author>

		<category term="소프트웨어 개발" scheme="http://kaistizen.net/EE/index.php/weblog/C17/" label="소프트웨어 개발" />

		<category term="프로젝트" scheme="http://kaistizen.net/EE/index.php/weblog/C12/" label="프로젝트" />
 
		<category term="마이크로소프트웨어" scheme="http://kaistizen.net/EE/index.php/weblog/" label="마이크로소프트웨어" />
 
		<category term="지속적인+통합" scheme="http://kaistizen.net/EE/index.php/weblog/" label="지속적인+통합" />

		<content type="xhtml">
			<div xmlns="http://www.w3.org/1999/xhtml">

								

					<div class="preface">
	<p>이 글은 월간 <a href="http://www.imaso.co.kr" title="월간 마이크로소프트웨어">마이크로소프트웨어</a>(일명 마소) 2008년 7월호에 기고한 글입니다. 물론 구성이나 내용 상의 차이가 있을 수 있습니다.</p>
</div>

<div class="main_title">			
	<blockquote>
		<p>비주얼 스튜디오 같은 IDE가 주를 이루는 개발 환경에서 빌드 스크립트는 찬밥 신세를 면치 못한 적도 있다. 그러나 빌드 스크립트는 IDE가 해주지 못하는 것. 빌드 자동화나 세밀한 빌드 구성을 지원한다. “왜 필요한가?” 싶다가도 막상 써보면 “이것 없이는 못 살아!”하게 된다. </p>
	</blockquote>
</div>

<br/>
			
<div class="who_is_author">
	<p><strong><a href="http://kaistizen.net" title="저자 블로그">최재훈</a></strong> | SK 아이미디어의 게임 서버 팀에서 일한다. 요즘은 스크립트 엔진을 개발하는 데 전념하며, 새로운 도전을 즐긴다. 직업 외적인 측면에선 배철수의 음악 캠프를 15년째 즐겨 듣고, U2가 최고의 밴드라 생각한다.</p>
</div>

<br/>




<div class="main_content">

	<h3>예제 소스 코드</h3>

	<p>이번 시간엔 제목 그대로 실제 사례를 놓고 따라해보면서 MSBuild의 사용법을 익혀볼 생각이다. 그러나 MSBuild를 본격적으로 다루는 첫 칼럼인 만큼 무리하게 복잡한 사례를 다룰 생각은 없다. MSBuild가 본래 목표로 삼은 프로그래밍 언어인 C#의 경우만 우선 다뤄보려 한다. csproj, 즉 C# 프로젝트 파일 자체가 MSBuild 스크립트에 불과하다는 사실만 봐도 MSBuild와 C# 프로젝트의 궁합은 정말 잘 맞는다. 그런 만큼 최소한 이번 칼럼 중에서 “너무 어려워서 못 따라하겠어!” 같은 내용은 없을 것이다. 약속한다. </p>

	<p>가능하면 실제 코드를 가지고 실습하면 좋겠단 생각이 든다. 원고 쓰느라 억지로 예제를 만들다 보면 현실 세계와 동떨어진 완성물이 나오는 탓이다. 우리가 프로그래밍을 할 땐 책에는 없는 문제와 부딪히기 마련인데, 원고를 위한 예제는 그런 면, 그러니까 예측 불가능함이 부족하다. 그래서 C#으로 개발한 오픈 소스 라이브러리를 하나 골라 실습해보기로 했다.</p>

	<p>Program#(<a href="http://aimlbot.sourceforge.net/">http://aimlbot.sourceforge.net/</a>)은 AIML(Artificial Intelligence Markup Language) 엔진 라이브러리다. AIML은 말 그대로 인공지능을 XML로 구현할 수 있게 만든 언어인데 채팅봇을 만들 때 쓴다(AIML이나 채팅봇의 기본 개념을 알고 싶다면 “디지털 생명체 연구: 채팅로봇(Chatterbot) 기술”, <a href="http://kidbs.itfind.or.kr/WZIN/jugidong/1115/111501.htm를">http://kidbs.itfind.or.kr/WZIN/jugidong/1115/111501.htm를</a> 읽어보길 바란다). 최근에 Program#을 한국어 환경에 맞춰 고치는 일을 짬짬이 하는 탓에 이 라이브러리를 자동화할 겸 이번 칼럼의 예제로 쓰기로 한다. </p>

	<p> 예제에서 쓸 Program#은 Release Version 2.5(<a href="http://aimlbot.svn.sourceforge.net/viewvc/aimlbot/tags/2.5/">http://aimlbot.svn.sourceforge.net/viewvc/aimlbot/tags/2.5/</a>)다. 한데 원래 소스 코드는 엔진 라이브러리, 윈폼 구현 예제, 웹 서비스 구현 예제, 테스트 코드 등이 각자 별도의 솔루션으로 구성되었기 때문에 빌드 자동화하기 불편하다. 그래서 원래 소스 코드를 AIMLProjects.vs2008.sln 라는 하나의 솔루션으로 묶었다. 이 소스 코드는 <a href="http://kaistizen.net/EE/images/uploads/imaso-200810.zip">imaso-200810.zip</a>에서 다운로드 받으면 된다.</p>

	<p><strong>여기서 잠깐!</strong> 솔루션 파일 이름이 뭐라고? AIMLProjects.vs2008.sln? 비주얼 스튜디오 2008? 이 칼럼은 비주얼 스튜디오 2005를 다룬다 하지 않았던가? 맞다. 실은 지난 몇 달 동안 비주얼 스튜디오 2005로 개발된 프로젝트를 비주얼 스튜디오 2008로 이전하는 작업을 해왔다. 그 기간 내내 똑같은 소스 코드를 비주얼 스튜디오 2005와 비주얼 스튜디오 2008 양쪽에서 돌려보며 컴파일은 되는지, 테스트는 잘 통과하는지 쭉 지켜봤다. 이러한 점진적인 이전 작업은 처음 하는 탓에 까다로운 문제가 많았는데 가능하면 이런 경험도 칼럼을 통해 전달하고 싶다. 물론 이러한 이전 작업을 이해하려면 사전 지식이 더 필요하다. 그래서 이번 칼럼에선 비주얼 스튜디오 2008을 기준으로 삼고자 한다.</p>


	<br/>

	<h3>빌드 스크립트의 기본적인 모양새</h3>

	<p>다운로드 받은 소스 코드를 “D:\workspace\imaso-2008-10”에 놓았다고 가정하자. 이 폴더를 열면 두 개의 파일과 6개의 폴더가 보인다. 이 칼럼에선 파일이 중요한데 하나는 앞서 설명한 AIMLProjects.vs2008.sln이고 다른 하나는 빌드 스크립트인 msbuild.xml이다. 물론 이 빌드 스크립트는 완성판이다. 말인즉, 복잡하다. 처음 MSBuild를 접하는 사람에겐 복잡하게 느껴질지 모른다. 그러니 이 칼럼에선 완성된 빌드 스크립트를 분해해 하나씩 다시 조립해나가자. 우선 [목록 1]을 보자.</p>

	<dl>
	<dt>[목록 1] 빌드 스크립트 </dt>
	<dd>
		<pre name="code" class="xml">
&lt;Project xmlns=&quot;http://schemas.microsoft.com/developer/msbuild/2003&quot;&gt;

&lt;Target Name=&quot;Clean&quot;&gt;
	&lt;Message Text=&quot;타겟: Clean&quot; /&gt;
&lt;/Target&gt;

&lt;Target Name=&quot;Build&quot;&gt;
	&lt;Message Text=&quot;타겟: Build&quot; /&gt;
&lt;/Target&gt;

&lt;Target Name=&quot;Rebuild&quot; DependsOnTargets=&quot;Clean; Build&quot;&gt;
	&lt;Message Text=&quot;타겟: Rebuild&quot; /&gt;
&lt;/Target&gt;

&lt;/Project&gt;
		</pre> 
	</dd>
	</dl>

	<p>보통 이렇게 코드를 짜는 것부터 한다. 어떤 빌드 스크립트를 짜든 이걸 뼈대로 삼고 살점을 붙이는 방식으로 일하면 된다. 이 스크립트엔 타겟(Target)이 세 개 있다. 하나는 Clean. 글자 그대로 정리하는 역할을 하게 된다. 빌드 산출물을 삭제하고 소스 코드를 처음 상태로 돌려놓는 역할을 하게 될 텐데 보통 bin, obj 폴더를 지우는 일이다. Build는 앞으로 소스 코드를 빌드하는 일을 하게 될 테고, Rebuild는 “다시 빌드”를 맡는다. 그리고 Rebuild는 보통 Clean과 Build를 순서대로 실행하는 것에 불과하다.</p>

	<blockquote cite="">
		<h4>타겟?</h4>

		<p>MSDN에선 Target을 “작업”이라 부르기도 한다. MSBuild의 빌드 스크립트를 구성하는 XML 구성요소는 크게 Item, Property, Target이 있다. 그런데 그 이름에서 짐작하듯 Item과 Property는 어떤 “값”을 나타내는 반면, Target만이 유일하게 “행동”을 정의한다. MSDN 라이브러리에서 “MSBuild - 작업 참조” 항목을 보면, Copy, Delete, Exec, ReadLinesFromFile, VCBuild 같은 타겟이 있는데 글자 그대로 파일이나 디렉터리를 복사하고 지우거나 어떤 프로그램을 실행시키는 등의 일을 한다. 타겟은 약 30개 정도 되는데 프로그래밍을 통해 확장 가능하다. 몇 차례 소개한 MSBuildCommunityTask도 이러한 확장 기능을 활용한 사례라 하겠다.</p>
	</blockquote> 


	<br/>


	<h3>MSBuild 바이너리 래퍼</h3>

	<p>첫 번째 빌드 스크립트를 만들었으니 실행시켜볼 차례다. 그런데 msbuild.exe의 경로가 참 사람 피곤하게 만든다. “C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\msbuild.exe”, 이런 경로를 어느 세월에 치고 있겠나! 다른 건 몰라도 버전 번호는 참 고약하다. </p>

	<p>그래서 우리는 프로젝트 폴더, 즉 “D:\workspace\imaso-2008-10”에 MsBuild_WIN32.bat란 배치 파일을 만들 생각이다. 실은 이 배치 파일은 지난 시간에 소개했는데, 이번에는 비주얼 스튜디오 2005를 쓰는 경우와 2008을 쓰는 경우를 비교해보자.</p>

	<dl>
	<dt>[목록 2] [VS2005 &amp; x86]를 위한 MSBuild_Win32.bat </dt>
	<dd>
		<pre>
@echo off
SET PATHSAVED=%PATH% &gt; _temp.txt
call &quot;%VS80COMNTOOLS%\..\..\VC\vcvarsall.bat&quot; x86 &gt;&gt; _temp.txt
&quot;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\msbuild.exe&quot; %*
SET ERR_LEVEL=%errorlevel%
SET PATH=%PATHSAVED% &gt;&gt; _temp.txt
SET PATHSAVED=&gt;&gt; _temp.txt
exit /b %ERR_LEVEL%
		</pre> 
	</dd>
	</dl>	

	<dl>
	<dt>[목록 3] [VS2005 &amp; x86]를 위한 MSBuild_Win32.bat </dt>
	<dd>
		<pre>
@echo off
SET PATHSAVED=%PATH% &gt; _temp.txt
call &quot;%VS90COMNTOOLS%\..\..\VC\vcvarsall.bat&quot; x86 &gt;&gt; _temp.txt
&quot;C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe&quot; %*
SET ERR_LEVEL=%errorlevel%
SET PATH=%PATHSAVED% &gt;&gt; _temp.txt
SET PATHSAVED=&gt;&gt; _temp.txt
exit /b %ERR_LEVEL%
		</pre> 
	</dd>
	</dl>

	<p>두 배치 파일의 차이점은 세 번째 줄과 네 번째 줄에 있다. 우선 세 번째 줄에선 비주얼 스튜디오 공통도구의 경로가 쓰이는데 당연히 버전에 따라 경로도 달라진다(%VS80COMNTOOLS% 와 %VS90COMNTOOLS%). </p>

	<p>네 번째 줄에선 MSBuild를 호출한다. 두말하면 잔소리지만, 비주얼 스튜디오 2005는 닷넷 프레임워크 2.0을 위해, 그리고 비주얼 스튜디오 2008은 닷넷 프레임워크 2.0부터 3.5 사이를 위해 개발됐다. 그러니 MSBuild 바이너리의 버전도 그에 맞춰야 한다.</p>

	<p>그러고 보니 이 배치 파일이 하는 일에 대해 자세히 설명한 적이 없다. 배치 파일을 쓸 일이 많지 않다 보니 이쯤에서 간략하게 알아두자. 우선 두 번째 줄에선 기본 경로 값을 저장한다. 명령창에서 “set” 명령을 실행시키면 PATH 값이 나오는데, 세 번째 줄에 있는 vcvarsall.bat 배치 파일이 이 값을 변경한다. 그러니 변경되기 전의 PATH 값을 미리 저장해뒀다가 모든 일이 다 끝나고 나서 복구하는데 쓸 생각이다. Vcvarsall.bat 는 비주얼 스튜디오에 필요한 환경설정을 구성한다. </p>

	<p>네 번째 줄에서 MSBuild를 실행시키는데 주목할 부분은 “%*”다. 이 기호는 배치 파일에 넘긴 모든 인자를 뜻한다. 예를 들어 이런 명령어를 쳤다고 해보자.</p>

	<pre>Msbuild_win32.bat msbuild.xml /t:build</pre>

	<p>그러면 네 번째 줄은 다음과 같이 해석된다.</p>

	<pre>&quot;C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe&quot;  msbuild.xml /t:build</pre> 

	<p>다섯 번째 줄에서 우리는 msbuild의 실행결과 값을 저장해놨다가 마지막 줄에서 반환한다. 그리고 여섯 번째 줄에서 세 번째 줄에서 바뀐 경로를 원래대로 돌려놓는다. 이로써 MSBuild의 래퍼 배치파일이 완성됐다. </p>

	<br/> 

	<h3>빌드 스크립트 실행해보기</h3>

	<p>우선 Clean부터 실행해보자. 지면상의 이유로 불필요한 출력 메시지는 삭제했으니 실제 실행결과는 좀더 복잡할 것이다.</p>

	<pre>D:\workspace\imaso-2008-10&gt; Msbuild_win32.bat msbuild.xml /t:Clean
Build started 2008-09-17 오전 9:53:48.
Project &quot;D:\workspace\imaso-2008-10\msbuild.xml&quot; on node 0 (Clean target(s)).
  타겟: Clean
Done Building Project &quot;D:\workspace\imaso-2008-10\msbuild.xml&quot; (Clean target(s)).

Build succeeded.
    0 Warning(s)
    0 Error(s)</pre> 

	<p>예상대로 '타겟: Clean'만 찍힌다. 명령창에 타겟 이름만 출력할 뿐 아직은 어떤 일도 하지 않는다. 이제 Build 타켓을 실행시켜보자.</p>

	<pre>D:\workspace\imaso-2008-10&gt; Msbuild_win32.bat msbuild.xml /t:Build
Build started 2008-09-17 오전 9:53:52.
Project &quot;D:\workspace\imaso-2008-10\msbuild.xml&quot; on node 0 (Build target(s)).
  타겟: Build
Done Building Project &quot;D:\workspace\imaso-2008-10\msbuild.xml&quot; (Build target(s)).

Build succeeded.
    0 Warning(s)
    0 Error(s)</pre>

	<p>DependsOnTargets 애트리뷰트에 명시한 대로 Clean과 Build 타겟이 순서대로 실행됐다. DependsOnTarget(그리고 설명 안 한 CallTarget)은 코드 중복을 줄이는데 도움이 된다. 가능하면 DependsOnTarget을 써먹자.</p>

	<p>여기까진 예상했던 대로다. 그런데 좀 색다르게 타겟 이름을 명시하지 않으면 어떻게 될까?</p>

	<pre>D:\workspace\imaso-2008-10&gt; Msbuild_win32.bat msbuild.xml 
Build started 2008-09-17 오전 9:53:48.
Project &quot;D:\workspace\imaso-2008-10\msbuild.xml&quot; on node 0 (Clean target(s)).
  타겟: Clean
Done Building Project &quot;D:\workspace\imaso-2008-10\msbuild.xml&quot; (Clean target(s)).</pre>

	<p>MSBuild 바이너리를 실행할 때 명령창에서 타겟 이름을 주지 않으면 처음 정의한 타겟을 실행한다. 이 경우엔 Clean 타겟을 실행했다. 만약 Build 타겟이 Clean 타겟보다 앞에 있었다면 Build 타겟이 실행됐을 것이다. </p>

	<p>눈치 빠른 이는 벌써 알아차렸겠지만 당연히 기본 타겟을 바꾸는 방법도 있다. </p>

	<dl>
	<dt>[목록 4] DefaultTargets</dt>
	<dd>
		<pre name="code" class="xml">
&lt;Project DefaultTargets=&quot;Build&quot; xmlns=&quot;http://schemas.microsoft.com/developer/msbuild/2003&quot;&gt;
중략…
&lt;/Project&gt;
		</pre> 
	</dd>
	</dl>

	<p>Project 엘레멘트의 DefaultTargets 애트리뷰트를 활용하면 된다. 이 경우엔 &quot;Build&quot;를 기본 타겟으로 삼았다. 이렇게 빌드 스크립트를 바꾸고 실행해보면 다음과 같은 결과를 얻는다.</p>

	<pre>D:\workspace\imaso-2008-10&gt; Msbuild_win32.bat msbuild.xml
Build started 2008-09-17 오전 9:54:07.
Project &quot;D:\workspace\imaso-2008-10\msbuild.xml&quot; on node 0 (default targets).
  타겟: Build
Done Building Project &quot;D:\workspace\imaso-2008-10\msbuild.xml&quot; (default targets).</pre>

	<p>DefaultTargets 라는 이름에 주의하자. DefaultTarget이 아닌 DefaultTargets다. 말인즉, 여러 개의 타겟을 한번에 지정해도 된다는 뜻이다. 예를 들어, DefaultTargets=&quot;Clean; Build&quot;라 지정하면 이런 결과가 나온다.</p>

	<pre>D:\workspace\imaso-2008-10&gt; Msbuild_win32.bat msbuild.xml
Build started 2008-09-17 오전 10:21:30.
Project &quot;D:\workspace\imaso-2008-10\msbuild.xml&quot; on node 0 (default targets).
  타겟: Build
Clean:
  타겟: Clean
Done Building Project &quot;D:\workspace\imaso-2008-10\msbuild.xml&quot; (default targets).</pre>

	<p>여기서 좀더 나아가볼까? 아예 파일 이름도 주지 않는 것이다.</p>


	<pre>D:\workspace\cuckoo-trunk\server\src\Aiml&gt; Msbuild_win32.bat
Build started 2008-09-18 오전 10:04:14.
Project &quot;D:\workspace\cuckoo-trunk\server\src\Aiml\AIMLProjects.vs2008.sln&quot; on node 0 (default targets).
  Building solution configuration &quot;Debug|Any CPU&quot;.</pre>


	<p>뭔가 달라졌다. &quot;D:\workspace\imaso-2008-10\msbuild.xml&quot;가 아닌 &quot;D:\workspace\cuckoo-trunk\server\src\Aiml\AIMLProjects.vs2008.sln&quot;을 실행시켰다. 만약 &quot;D:\workspace\cuckoo-trunk\server\src\Aiml\AIMLProjects.vs2008.sln&quot;을 지우거나 확장자를 “sln.txt”로 바꾼다면 어떨까? 그러면 “Msbuild_win32.bat msbuild.xml /t:Clean”과 같은 결과를 얻는다. </p>

	<p>정리하면 이렇다. 만약 빌드 스크립트를 명시하지 않으면 해당 폴더에 있는 솔루션 파일부터 찾는다. 솔루션 파일이 없으면 &quot;어라, 파일 이름은 어디 갔지? 에라 모르겠다. 아마 msbuild.xml이겠지. 아니면 말고.&quot; 이렇게 생각한다. 그러니 주 빌드 스크립트 파일의 이름은 msbuild.xml로 짓는 편이 좋다. 여기서 주 빌드 스크립트라 함은 부 빌드 스크립트도 있다는 뜻인데, 훗날 MSBuildCommunityTasks를 다룰 때 알아볼 것이다. </p>


	<br/>

	<h3>진짜 빌드해보기</h3>

	<p>이제 진짜 빌드를 해보자. 우선 Build 타겟부터 구현해보는 게 어떨까?</p>

	<dl>
	<dt>[목록 5] Build 타겟 </dt>
	<dd>
		<pre name="code" class="xml">
&lt;Project DefaultTargets=&quot;Build&quot; xmlns=&quot;http://schemas.microsoft.com/developer/msbuild/2003&quot;&gt;
&lt;PropertyGroup&gt;
    &lt;Configuration Condition=&quot; '$(Configuration)' == '' &quot;&gt;Debug&lt;/Configuration&gt;
    &lt;Platform Condition=&quot; '$(Platform)' == '' &quot;&gt;Any CPU&lt;/Platform&gt;
	&lt;BuildCondition&gt;$(Configuration)|$(Platform)&lt;/BuildCondition&gt;
&lt;/PropertyGroup&gt;

&lt;PropertyGroup Condition=&quot; '$(BuildCondition)' == 'Debug|AnyCPU' &quot;&gt;
&lt;/PropertyGroup&gt;

&lt;PropertyGroup Condition=&quot; '$(BuildCondition)' == 'Release|AnyCPU' &quot;&gt;
&lt;/PropertyGroup&gt;

&lt;ItemGroup&gt;
	&lt;ProjectReferences Include=&quot;AIMLProjects.vs2008.sln&quot;&gt;
		&lt;Configuration&gt;$(Configuration)&lt;/Configuration&gt;
		&lt;Platform&gt;$(Platform)&lt;/Platform&gt;
	&lt;/ProjectReferences&gt;
&lt;/ItemGroup&gt;
		
&lt;Target Name=&quot;Clean&quot;&gt;
	&lt;Message Text=&quot;타겟: Clean&quot; /&gt;
&lt;/Target&gt;

&lt;Target Name=&quot;Build&quot;&gt;
	&lt;Message Text=&quot;타겟: Build&quot; /&gt;
	&lt;Message Text=&quot;빌드 조건: '$(BuildCondition)'&quot; Importance=&quot;high&quot; /&gt;
	
	&lt;MSBuild Projects=&quot;@(ProjectReferences)&quot; Properties=&quot;Configuration=%(ProjectReferences.Configuration);Platform=%(ProjectReferences.Platform)&quot; StopOnFirstFailure=&quot;true&quot; /&gt;
&lt;/Target&gt;

&lt;Target Name=&quot;Rebuild&quot; DependsOnTargets=&quot;Clean; Build&quot;&gt;
	&lt;Message Text=&quot;타겟: Rebuild&quot; /&gt;
&lt;/Target&gt;
&lt;/Project&gt;

		</pre> 
	</dd>
	</dl>
	
	<p>MSBuild엔 크게 세 가지 구성요소가 있다 했다. 이 빌드 스크립트에서 그 구성요소를 모두 확인할 수 있는데, Item, Property, Target이다. Target은 이미 다뤘고, 우선 Property에 대해 알아보자. Property는 PropertyGroup 안에 정의하는데 PropertyGroup 자체는 Property를 묶는 역할만 할 뿐이다. Property는 프로그래밍 언어의 변수 정도를 떠올리면 이해하기 쉽다. Configuration이란 변수와 Platform이란 변수를 만들어 빌드 설정값을 저장하는 용도로 쓴다. Property 값은 명령어 인자로 넘길 수 있는데 이런 식이다.</p>

	<pre>Msbuild msbuild.xml /p:Configuration=Release</pre>

	<p>이렇게 빌드 스크립트를 돌리면 Configuration 프로퍼티의 값은 Release가 되고, Platform 프로퍼티의 값은 Any CPU가 된다. </p>
      
	<p>Item은 일종의 배열이다. 특히, 파일 이름과 기타 정보를 저장하는 용도로 쓰는 배열이다. ProjectReferences란 배열이 보이는데, 이 배열엔 AIMLProjects.vs2008.sln 이란 파일만 들어있다. 그리고 이 요소는 Configuration과 Platform이란 두 개의 멤버 변수를 가진다. 사실, 이 경우엔 멤버 변수를 따로 정의할 필요 없이 Configuration, Platform 프로퍼티를 쓰면 된다. 하지만 프로젝트 구성이 복잡한 경우, 예를 들어 C++ 프로젝트의 플랫폼은 WIN32이고 C# 프로젝트의 플랫폼은 x86이 되어야 하는 경우라면 이렇게 Item마다 별도의 설정값을 가져야 한다.</p>
	<p>이제 빌드 스크립트를 돌려보고 빌드가 잘 되는지 확인해보자.</p>

	<pre>Msbuild_win32.bat msbuild.xml /t:Build</pre>

	<br/>

	<h3>Clean하기</h3>

	<dl>
	<dt>[목록 6] Clean 타겟</dt>
	<dd>
		<pre name="code" class="xml">
&lt;Project DefaultTargets=&quot;Build&quot; xmlns=&quot;http://schemas.microsoft.com/developer/msbuild/2003&quot;&gt;

중략…
		
&lt;Target Name=&quot;Clean&quot;&gt;
	&lt;Message Text=&quot;타겟: Clean&quot; /&gt;
	
	&lt;MSBuild Projects=&quot;@(ProjectReferences)&quot; Targets 
=&quot;Clean&quot; Properties=&quot;Configuration=%(ProjectReferences.Configuration);Platform=%(ProjectReferences.Platform)&quot; StopOnFirstFailure=&quot;true&quot; /&gt;
&lt;/Target&gt;
&lt;/Project&gt;
		</pre> 
	</dd>
	</dl>

	<p>알다시피 비주얼 스튜디오 프로젝트나 솔루션에 이미 Clean 구성(Configuration)이 있다. 그러니 Clean 타겟에서 이를 호출하면 될 것 같다. 일단 정말 그런지 확인해볼까?</p>

	<pre>msbuild msbuild.xml /t:Clean</pre>

	<p>정말 깔끔하게 정리됐을까? 물론 명령창에 뜨는 빌드 정보는 성공했다(Build succeeded.)고 하지만 직접 확인해봐야 안심하겠다. </p>

	<dl>
	<dt>그림 1. Clean이 잘 안 됐다.</dt>
	<dd>
	
	</dd>
	</dl>

	<p>.\AIMLGUI\AIMLGUI\bin\debug 폴더(그림 1)에 가 보니 여전히 일부 파일이 남아 있다. CustomTags는 빌드 이벤트를 활용해 만든 폴더라 자동으로 정리(Clean)가 안 됐고 그 외에도 비주얼 스튜디오가 디버깅할 때 자동으로 만든 파일(*.vshost.*)도 있다. 역시 가장 좋은 방법은 bin 폴더를 통째로 지우는 것이다.</p>

	<dl>
	<dt>[목록 7] Clean 타겟 ? 두 번째 시도</dt>
	<dd>
		<pre name="code" class="xml">
&lt;Project DefaultTargets=&quot;Build&quot; xmlns=&quot;http://schemas.microsoft.com/developer/msbuild/2003&quot;&gt;

중략 …

&lt;!-- Clean 할 대상 디렉터리 --&gt;
&lt;ItemGroup&gt;
	&lt;BinDirs Include=&quot;.\AIMLbot\AIMLbot\bin&quot; /&gt;
	&lt;BinDirs Include=&quot;.\AIMLGUI\AIMLGUI\bin&quot; /&gt;
	&lt;BinDirs Include=&quot;.\AIMLWebService\AIMLWebService\bin&quot; /&gt;
	&lt;BinDirs Include=&quot;.\ExampleCustomAIMLTags\ExampleCustomAIMLTags\bin&quot; /&gt;
	&lt;BinDirs Include=&quot;.\Shared\bin&quot; /&gt;
	&lt;BinDirs Include=&quot;.\Tests\Tests\bin&quot; /&gt;
	
	&lt;ObjDirs Include=&quot;.\AIMLbot\AIMLbot\obj&quot; /&gt;
	&lt;ObjDirs Include=&quot;.\AIMLGUI\AIMLGUI\obj&quot; /&gt;
	&lt;ObjDirs Include=&quot;.\AIMLWebService\AIMLWebService\obj&quot; /&gt;
	&lt;ObjDirs Include=&quot;.\ExampleCustomAIMLTags\ExampleCustomAIMLTags\obj&quot; /&gt;
	&lt;ObjDirs Include=&quot;.\Shared\obj&quot; /&gt;
	&lt;ObjDirs Include=&quot;.\Tests\Tests\obj&quot; /&gt;
&lt;/ItemGroup&gt;

&lt;Target Name=&quot;Clean&quot;&gt;
	&lt;Message Text=&quot;타겟: Clean&quot; /&gt;
	
	&lt;MSBuild Projects=&quot;@(ProjectReferences)&quot; Targets 
=&quot;Clean&quot; Properties=&quot;Configuration=%(ProjectReferences.Configuration);Platform=%(ProjectReferences.Platform)&quot; StopOnFirstFailure=&quot;true&quot; /&gt;

	&lt;RemoveDir Directories=&quot;@(BinDirs);@(ObjDirs)&quot; /&gt;
&lt;/Target&gt;
&lt;/Project&gt;

		</pre> 
	</dd>
	</dl>

	<p>조금 번거롭긴 하지만 지워야 할 대상 폴더의 목록(BinDirs, ObjDirs)을 만들었다. 그리고 RemoveDir 을 써서 대상 폴더를 모두 삭제했다. 이 방법은 상당히 효과적이지만 귀찮은 점도 있다. 무엇보다 대상 폴더의 목록을 만들고 꾸준히 갱신해야 한다는 점이 성가시다. 다행히 Item에 와일드카드를 쓸 수 있다. 이를테면 [목록 8]처럼 말이다.</p>

	<dl>
	<dt>[목록 8] Clean 타겟 ? 세 번째 시도</dt>
	<dd>
		<pre name="code" class="xml">
&lt;Project DefaultTargets=&quot;Build&quot; xmlns=&quot;http://schemas.microsoft.com/developer/msbuild/2003&quot;&gt;

중략…

&lt;!-- Clean 할 대상 디렉터리 --&gt;
&lt;ItemGroup&gt;	
	&lt;FilesInBinDirs Include=&quot;**\**\bin\$(Configuration)\*&quot; /&gt;
	&lt;FilesInBinDirs Include=&quot;**\bin\$(Configuration)\*&quot; /&gt;
	
	&lt;FilesInObjDirs Include=&quot;**\**\obj\$(Configuration)\*&quot; /&gt;
	&lt;FilesInObjDirs Include=&quot;**\obj\$(Configuration)\*&quot; /&gt;
&lt;/ItemGroup%gt;
	
&lt;!-- 타겟 시작 --&gt;	
&lt;Target Name=&quot;Clean&quot;&gt;
	&lt;Message Text=&quot;타겟: Clean&quot; Importance=&quot;high&quot; /&gt;	
	
	&lt;MSBuild Projects=&quot;@(ProjectReferences)&quot; Targets 
=&quot;Clean&quot; Properties=&quot;Configuration=%(ProjectReferences.Configuration);Platform=%(ProjectReferences.Platform)&quot; StopOnFirstFailure=&quot;true&quot; /&gt;

	&lt;Delete Files=&quot;@(FilesInBinDirs);@(FilesInObjDirs)&quot; /&gt;
&lt;/Target&gt;
&lt;/Project&gt;

		</pre> 
	</dd>
	</dl>
	
	<p>이 방법은 간단하고 효과적이지만 여전히 문제가 없진 않다. 이렇게 저렇게 테스트를 많이 해봤지만 Item에 와일드카드를 쓰면 아무래도 폴더 지정이 안 되는 듯 하다. 그러니까 bin\debug\ 에 있는 모든 파일을 지우라고 하는 것보단 bin\debug 폴더를 통째로 지우라고 하는 편이 직관적이고 확실하게 정리(Clean)하는 방법이다. 하지만 여러 차례 시도해봤지만 번번히 실패했다. 혹 이 문제를 해결할 방법이 있을지도 모른다. 만약 방법을 찾게 되면 블로그를 통해 전달하도록 하겠다.</p>	

	<br/>
	
	<div class="concluding_remarks">
		<h3>끝마치는 말</h3>
	
		<p>자, MSBuild의 기초는 익혔다. 다음 시간엔 MSBuild로 복잡한 일을 다루는 방법에 대해 알아보겠다. 지면이 허락하고 진도가 충분히 빠졌다는 판단이 들면 아마 여러분이 어디서도 보지 못한 신선한 사례도 다룰 수 있을 것이다. 기대하시라. </p>
	</div>

	
</div>






												
				<br/>
				
<p><a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/80x15.png" /></a><br/>
이 저작물은 <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/">크리에이티브 커먼즈 코리아 저작자표시-동일조건변경허락 2.0 대한민국 라이센스</a>에 따라 이용하실 수 있습니다.</p>

			</div>
		</content>
	</entry>

	<entry>
		<title>실전! 지속적인 통합 9편</title>
				<link rel="alternate" type="text/html" href="http://kaistizen.net/EE/index.php/imaso/continuousintegration_2008_09/" />
				
		<id>tag:kaistizen.net,2008:EE/index.php/weblog/index/2.1440</id>
		<published>2008-11-29T16:28:27Z</published>
		<updated>2008-11-29T16:49:04Z</updated>
		<author>
			<name>최재훈</name>
			<email>kaistizen@gmail.com</email>
			<uri>http://kaistizen.net</uri>		</author>

		<category term="소프트웨어 개발" scheme="http://kaistizen.net/EE/index.php/weblog/C17/" label="소프트웨어 개발" />

		<category term="프로젝트" scheme="http://kaistizen.net/EE/index.php/weblog/C12/" label="프로젝트" />
 
		<category term="마이크로소프트웨어" scheme="http://kaistizen.net/EE/index.php/weblog/" label="마이크로소프트웨어" />
 
		<category term="지속적인+통합" scheme="http://kaistizen.net/EE/index.php/weblog/" label="지속적인+통합" />

		<content type="xhtml">
			<div xmlns="http://www.w3.org/1999/xhtml">

								

					<h3 class="MsoNormal"><strong style="">빌드 자동화의 핵심 <span>– MSBuild</span></strong></h3>
<p>&nbsp;</p>
<p class="MsoNormal"><span style="">지속적인 통합은 단순히 생각하면 빌드 자동화</span>, 컴파일 자동화에 불과하다<span>.</span> 이 말은 지난달 칼럼의 첫 문장이다<span>.</span> 물론 정말로 지속적인 통합의 가치가 그 정도뿐이라 폄하하자는 건 아니고<span>,</span> 자동화를 이루고 개발자 테스트를 도입하면 더 나은 품질을 기대할 수 있다는 점을 보여주려는 의도에서 한 말이다<span>.</span> 하지만 자동화는 말로는 쉬워도 막상 해보면 만만치 않다<span>.</span> 소스 코드를 자동으로 빌드하고 데이터베이스를 생성하고 단위 테스트를 돌리며<span>,</span> 그 결과를 누구나 알기 쉽게 보여주는 단일 소프트웨어란 존재하지 않기 때문이다<span>.</span> 그러나 <span>MSBuild</span>를 사용하면 좀더 편리하게 자동화를 도모할 수 있다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<div class="section" style="background-color: rgb(249, 249, 216);">
<p class="MsoNormal"><strong style=""><span>[</span>필자 소개<span>]</span> 최재훈</strong> <span><a href="http://kaistizen.net/">http://kaistizen.net</a>, <a href="http://kaistizen.springnote.com/pages/mailto:kaistizen@gmail.com">kaistizen@gmail.com</a> SK</span> 아이미디어의 게임 서버 팀에서 일한다<span>.</span> 요즘은 스크립트 엔진을 개발하는 데 전념하며<span>,</span> 새로운 도전을 즐긴다<span>.</span> 직업 외적인 측면에선 배철수의 음악 캠프를 <span>15</span>년째 즐겨 듣고<span>, U2</span>가 최고의 밴드라 생각한다<span>.</span></p>
</div>
<p>&nbsp;</p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal">봄<span>,</span> 여름<span>, 2</span>분기 동안 우리는 무엇을 공부했는가<span>?</span> 처음엔 버전 관리 시스템인 서브버전<span>(Subversion)</span>을 도입했으며<span>,</span> 이어서 지속적인 컴파일에 대해 알아봤다<span>.</span> 비주얼 스튜디오와 빌드 서버인 <span>CruiseControl .NET</span>을 이용해 기초적인 컴파일 자동화를 꾀했다<span>.</span> 여기까지 해보니 어느새 봄을 지나 여름이 왔다<span>.</span> 여름엔 <span>C++</span>용 단위 테스트 라이브러리인 <span>UnitTest++</span>를 이용해 단위 테스트를 구성했다<span>.</span> 그리고 가을이 왔다<span>.</span></p>
<p>&nbsp;</p>
<p>이젠 기초를 갖추었으니 좀더 그럴듯한 자동화를 꾀해보자<span>.</span> 여태껏 컴파일 자동화<span>,</span> 단위 테스트 자동화를 따로따로 도입했다면<span>,</span> 이제부턴 이 모든 것을 한데 엮어 하나의 완성품으로 승화시켜보자<span>.</span> 그러려면 무엇보다 모든 조각을 묶어줄 뭔가가 필요한데<span>,</span> 바로 빌드 스크립트가 필요한 시점이다<span>.</span></p>
<p>&nbsp;</p>
<h3>빌드 스크립트의 의의</h3>
<p>&nbsp;</p>
<p class="MsoNormal">그런데 도대체 빌드 스크립트가 무엇이길래 이런 중요한 역할을 맡는단 말인가<span>?</span></p>
<p>&nbsp;</p>
<p>이렇게 생각해보자<span>.</span> 소스 코드를 빌드하고 데이터베이스를 적절히 갖추고 단위 테스트를 돌린 다음 우리가 개발한 게임 서버를 실행시켜 자동화 못 시킨 부분을 사람이 직접 돌려볼 수 있게 하려 한다<span>.</span> 물론 이 모든 과정을 사람이 직접 해도 되지만<span>,</span> 한창 개발 중인 시점이라 하루에도 똑같은 과정을 수십 번씩 반복하는 상황이라면 과연 어떨까<span>?</span> 과거엔 이렇게 귀찮고 짜증나는 일은 신입 개발자의 몫이었다<span>.</span> 핵심 개발자들이 신나게 소스 코드를 만지작거리며 무언가 멋진 기능을 완성하는 즐거움을 누릴 때<span>,</span> 부푼 꿈을 안고 회사에 들어온 신입 개발자들은 소스 코드를 구경조차 못하고 잡다한 일을 처리하는 심부름꾼으로 전락하곤 했다<span>.</span></p>
<p>&nbsp;</p>
<p>이런 불합리함을 과거엔 <span>‘</span>배우는 과정<span>’</span>이라며 합리화시켰지만<span>,</span> 사람 구하기 힘들다는 요즘엔 이래선 곤란하다<span>.</span> 그래서 우리는 자동화를 꾀한다<span>.</span> 그런데 이것이 말처럼 쉽지 않다<span>.</span> 테스트를 할 땐 <span>DEBUG</span> 빌드를 하고 출시 전엔 <span>RELEASE</span> 빌드를 해야 한다<span>(</span>실제론 상황에 따라 다르다<span>). 64</span>비트로 컴파일해야 하는 애플리케이션이 있는가 하면 <span>32</span>비트 컴파일만 가능한 애플리케이션도 있다<span>.</span> 이렇게 설정 값이 다양한데 컴파일만 하는 것도 아니다<span>.</span> 테스트를 돌리고 데이터베이스에 접속해 필요한 스키마와 데이터를 생성해야 한다<span>.</span></p>
<p>&nbsp;</p>
<p>빌드 자동화라는 말 한마디에 속으면 안 된다<span>.</span> 실제 프로젝트에선 다양한 빌드가 존재한다<span>.</span> 평소 땐 <span>/RTC(Run-Tie Error Checks)</span> 옵션과 함께 <span>DEBUG</span> 빌드를 돌려서 좀더 미묘한 오류를 잡아내고<span>,</span> 하루에 한번 정도는 시간이 오래 걸리는 <span>RELEASE</span> 빌드를 돌린다<span>.</span> 출시일이 다가오면 빌드와 더불어 패키징 작업까지 해본다<span>.</span> 이런 식으로 여러 형태의 빌드를 전부 다루고<span>,</span> 앞서 언급한 것처럼 여러 형태의 기술<span>(</span>데이터베이스<span>,</span> 프로그래밍 언어 등<span>)</span>을 쉽게 조작할 수 있어야 한다<span>.</span></p>
<p>&nbsp;</p>
<p>이때 <span>MSBuild</span>나 <span>NAnt</span> 같은 빌드 스크립트가 도움이 된다<span>.</span> 일반적으로 빌드 스크립트엔 빌드시 일상적으로 쓰이는 기술<span>(</span>데이터베이스나 레지스트리 조작 등<span>)</span>이 내장된다<span>.</span> 또한 익히기도 비교적 쉬워서 파이썬 같은 범용 스크립트 언어로 빌드 자동화를 꾀하는 것보다 생산성이 높다<span>.</span> 더군다나 <span>MSBuild</span> 같은 유명한 빌드 스크립트는 <span>CruiseControl .NET</span> 같은 다른 빌드 도구와도 연동된다는 장점까지 있다<span>.</span> 그래서 팀 내에 적어도 한 명은 빌드 스크립트를 익혀야 한다<span>.</span></p>
<p>&nbsp;</p>
<p>빌드 스크립트를 써야 하는 이유를 장황하게 설명했지만 요약하면 아주 간단하다<span>.</span></p>
<p>&nbsp;</p>
<ol>
<li>빌드 때 자주 쓰는 기능이 내장되어 있다<span>.</span></li>
<li>범용 스크립트 언어보다 익히기 쉽고 생산성 측면에서 이점이 있다<span>.</span></li>
<li>다른 빌드 도구<span>(</span>예<span>. CruiseControl .NET)</span>과 연동하기 쉽다<span>.</span></li>
</ol>
<p>&nbsp;</p>
<h3>왜 <span>MSBuild</span>인가<span>?</span></h3>
<p>&nbsp;</p>
<p class="MsoNormal">빌드 스크립트는 참 종류가 많다<span>.</span> 그런데 굳이 <span>MSBuild</span>를 써야 할 이유가 있을까<span>?</span> 우선 이 칼럼은 윈도우 플랫폼에서 <span>x64</span> 애플리케이션을 개발하는 경우를 상정한다<span>.</span> 그러니 <span>Java</span>용으로 개발된 <span>Ant</span> 같은 빌드 스크립트는 제외하자<span>. C++</span> 세계에선 오래 전부터 빌드 자동화의 할아버지 <span>make</span>를 주로 써왔다<span>.</span> 물론 아직도 <span>make</span>의 위력은 건재하다<span>.</span> 하지만 신입 개발자일 적을 돌아보면 <span>make</span>는 너무 어려웠다<span>.</span> 복잡한 암호를 보는 듯한 기분이랄까<span>? @</span>나 <span>$</span> 같은 기호가 난무하기 때문이었던 것 같다<span>.</span> 어쨌거나 <span>make</span>는 익히기 쉽지 않을뿐더러 최근에 개발된 <span>XML</span>형 빌드 스크립트와 비교하면 생산성이 떨어지는 문제도 있다<span>. MSBuild</span>나 <span>NAnt</span>는 다른 빌드 도구와 쉽게 연동이 된다<span>.</span> 무엇보다 빌드 결과를 <span>XML</span> 형태로 출력하거나 다른 도구가 뱉어낸 <span>XML</span> 출력 결과를 읽기 쉬워야 하는데<span>, make</span>는 이러한 부분이 부족하다<span>.</span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><strong style=""><span>[</span>목록 <span>1] make</span> 예제<span>(</span>출처<span>. Wikipedia)</span></strong></p>
<ol class="code">
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">helloworld: helloworld.o</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">cc -o $@ $&lt;</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">helloworld.o: helloworld.c</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">cc -c -o $@ $&lt;</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">.PHONY: clean</span>&nbsp;</p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">clean:</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">rm -f helloworld helloworld.o</span></p>
</li>
</ol>
<p>&nbsp;</p>
<p class="MsoNormal">닷넷 프레임워크가 출시되고 나서 윈도우 세계에선 <span>NAnt(<a href="http://nant.sourceforge.net/">http://nant.sourceforge.net/</a>)</span>와 <span>MSBuild</span>가 차세대 빌드 스크립트로 떠올랐다<span>. NAnt</span>는 더 오래됐고 그만큼 다양한 기능을 제공한다<span>.</span> 하지만 <span>NAnt</span>는 사실상 개발이 중지되거나 개발 속도가 느리다<span>. 2007</span>년 <span>12</span>월에 <span>0.86</span> 베타 <span>1</span>이 출시된 게 고작이니 말이다<span>.</span></p>
<p>&nbsp;</p>
<p>그에 비해 <span>MSBuild</span>는 출시 이후 꾸준하지만 빠른 성장을 보였다<span>. “</span>추천 도구<span>”</span> 절에서 소개할 <span>MSBuildTasks</span> 같은 <span>MSBuild</span> 확장 라이브러리도 나와있어 기본적으로 제공되지 않는 기능을 쉽게 추가할 수 있으며<span>,</span> 무엇보다 마이크로소프트 사가 직접 개발하는 빌드 도구인 만큼 비주얼 스튜디오 같은 개발 도구와의 연동도 비교적 쉽다<span>.</span></p>
<p>&nbsp;</p>
<p>이러한 이유 때문에 이 칼럼에선 <span>MSBuild</span>를 주 빌드 스크립트로 활용할 것이며<span>,</span> 부족한 부분은 <span>MSDOS</span> 배치 파일 등을 통해 보충할 생각이다<span>.</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3><span>MSBuild</span>로 비주얼 스튜디오 솔루션<span>(.sln)</span>을 빌드하기</h3>
<p class="MsoNormal"><span>MSBuild</span> 바이너리는 닷넷 프레임워크와 함께 배포되며 보통 <span>C:WINDOWSMicrosoft.NETFrameworkv2.0.50727msbuild.exe</span> 같은 경로를 취한다<span>.</span> 이때 해당 소스 코드가 참조하는 닷넷 프레임워크 버전에 맞춰 경로를 잡아야 한다<span>.</span> 또 <span>64</span>비트 컴파일을 할 거라면<span>Framework</span>가 아닌 <span>Framework64</span>를 선택해야 한다<span>.</span></p>
<p>&nbsp;</p>
<p class="MsoNormal">&nbsp;</p>
<h3><span>64</span>비트 빌드엔 <span>MSBuild</span>가 필수다</h3>
<p class="MsoNormal"><span>“</span>윈도우 프로젝트 필수 유틸리티<span>”</span>란 책에는 다음과 같은 대목이 있다<span>.</span></p>
<p>&nbsp;</p>
<blockquote>
<p class="MsoNormal" style="margin-left: 20pt;"><span>&lt;devenv&gt;</span> 를 사용하면 <span>Release</span> 모드와 <span>Debug</span> 모드를 구분해서 빌드할 수 있지만<span>, 32, 64</span>비트 빌드를 구분해서 할 수는 없습니다<span>. &lt;devenv&gt;</span>에서 <span>64</span>비트 빌드를 하려면 프로젝트 설정에서 <span>Win32</span> 플랫폼은 삭제하고 <span>x64</span>만 남겨두어야 합니다<span>. VCBuild</span>는 <span>Release</span> 모드와 <span>Debug</span> 모드를 구분해서 빌드할 수 있고<span>, 32, 64</span>비트 빌드를 구분하여 할 수 있습니다<span>.</span></p>
</blockquote>
<p>&nbsp;</p>
<p class="MsoNormal">여기서 말하는 <span>devenv</span> 엘레멘트는 <span>CruiseControl .NET</span>의 설정 파일인 <span>ccnet.config</span>에서 사용된다<span>.</span> 우선 책에서 말한 내용이 사실인지 검증부터 해보자<span>.</span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><strong style=""><span>[</span>목록 <span>2] CCNet.config</span>의 비주얼 스튜디오 태스크</strong></p>
<ol class="code">
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;devenv&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">&lt;solutionfile&gt;srcMyProject.sln&lt;/solutionfile&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">&lt;configuration&gt;Debug&lt;/configuration&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">&lt;buildtype&gt;Build&lt;/buildtype&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">&lt;project&gt;MyProject&lt;/project&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">&lt;executable&gt;c:program filesMicrosoft Visual Studio .NETCommon7IDEdevenv.com&lt;/executable&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">&lt;buildTimeoutSeconds&gt;600&lt;/buildTimeoutSeconds&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">&lt;version&gt;VS2002&lt;/version&gt;</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;/devenv&gt;</span></p>
</li>
</ol>
<p>&nbsp;</p>
<p class="MsoNormal"><span>CruiseControl .NET</span> 홈페이지에서 문서의 <span>“Visual Studio Task”</span>라는 항목을 확인하면<span>, [</span>목록 <span>2]</span>과 같은 전체 예제가 있다<span>.</span> 예제를 보면 <span>&lt;devenv&gt;</span> 엘레멘트 아래에 <span>7</span>가지 엘레멘트가 쓰인다<span>.</span> 솔루션 파일을 지정하고<span>(solutionfile), DEBUG</span> 빌드인지 <span>RELEASE</span> 빌드인지 구분하고<span>(configuration), Rebuild, Build, Clean</span> 중 어떤 빌드 유형을 선택할 건지 고른다<span>(buildtype).</span> 그러나 어디에도 플랫폼<span>,</span> 그러니까 <span>32</span>비트 빌드인지 <span>64</span>비트 빌드인지 구분하는 <span>XML</span> 엘레멘트<span>(Element)</span>가 보이지 않는다<span>.</span> 그러니 책에서 말한 대로 <span>&lt;devenv&gt;</span> 엘레멘트를 써선 안 된다<span>.</span></p>
<p>&nbsp;</p>
<p>다행스럽게도 이 문제는 <span>MSBuild</span>를 쓰면 쉽게 해결된다<span>. MSBuild</span> 스크립트에서 윈도우 솔루션 파일을 빌드하고<span>, ccnet.config</span>에선 이 스크립트를 실행시키면 된다<span>.</span> 단<span>,</span> 몇 가지 주의할 점이 있다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<p>&nbsp;</p>
<h3><span>C#</span> 프로젝트는 쉽다</h3>
<p class="MsoNormal"><span>C#</span> 같은 순수 닷넷 프로젝트라면 빌드 자동화가 쉽다<span>.</span> 지속적인 통합 <span>5</span>편에서 언급한 바 있듯<span>, C#</span> 프로젝트 파일<span>(.csproj)</span> 및 솔루션 파일<span>(.sln)</span>은 그 자체가 <span>MSBuild</span> 스크립트에 불과하다<span>.</span> 그래서 다음과 같이 <span>ccnet.config</span>를 구성해도 된다<span>.</span></p>
<p>&nbsp;</p>
<ol class="code">
<li>
<p class="MsoNormal">&nbsp;<span style="font-size: 8pt;">&lt;tasks&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">&lt;msbuild&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 4em;"><span style="font-size: 8pt;">&lt;executable&gt;C:WINDOWSMicrosoft.NETFrameworkv2.0.50727MSBuild.exe&lt;/executable&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 4em;"><span style="font-size: 8pt;">&lt;workingDirectory&gt;C:srcMyProject -mainbuildtrunkserversrcConsoleApplication &lt;/workingDirectory&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 4em;"><span style="font-size: 8pt;">&lt;projectFile&gt;ConsoleApplication .sln&lt;/projectFile&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 4em;"><span style="font-size: 8pt;">&lt;buildArgs&gt;/noconsolelogger /p:Configuration=Debug;Platform=Win32 /v: minimal&lt;/buildArgs&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 4em;"><span style="font-size: 8pt;">&lt;logger&gt;C:Program Files (x86)CruiseControl.NETserverThoughtWorks.CruiseControl.MSBuild.dll&lt;/logger&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">&lt;/msbuild&gt;</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;/tasks&gt;</span></p>
</li>
</ol>
<p class="MsoNormal">&nbsp;</p>
<p>&nbsp;</p>
<h3><span>C++</span> 프로젝트는 특별하다</h3>
<p class="MsoNormal">안타깝게도 <span>MSBuild</span> 바이너리는<span>C++</span> 프로젝트는 빌드하지 못한다<span>.</span> 단 별도의<span>MSBuild</span> 스크립트를 만들면 방법이 있다<span>. MSBuild</span>엔 <span>&lt;msbuild&gt;</span>란 태스크가 있는데<span>,</span> 여기에 솔루션 파일 이름을 적어주면 대부분 빌드가 된다<span>.</span> 한데 <span>msbuild</span> 태스크는 비주얼 스튜디오 바이너리<span>(devenv.exe)</span>를 호출하지 않고<span>, VCBuild</span> 바이너리를 호출한다<span>.</span> 이는 <span>IDE</span> 종속성을 제거한다는 측면에서 바람직하지만<span>,</span> 안타깝게도 <span>devenv</span>와 <span>VCBuild</span>가 항상 똑같은 방식으로 작동하는 건 아니다<span>.</span> 특히 <span>C++/CLI</span> 기술을 쓰는 경우엔 비주얼 스튜디오로는 빌드가 되던 솔루션을<span>MSBuild</span>로 빌드하려면 실패하는 일이 잦다<span>(</span><strong style="">참고</strong><span>. <a href="http://kaistizen.net/EE/index.php/weblog/comments/cplusplus_cli_and_x64_and_msbuild/">http://kaistizen.net/EE/index.php/weblog/comments/cplusplus_cli_and_x64_and_msbuild/</a>).</span></p>
<p>&nbsp;</p>
<p>이땐<span>, MSBuild</span>의 <span>&lt;Exec&gt;</span> 태스크를 사용하여 <span>Devenv</span>를 직접 호출하면 된다<span>.</span> 비주얼 스튜디오 바이너리는 설정<span>(Configuration)</span>값과 플랫폼<span>(Platform)</span>값을 매개변수로 받기 때문에 앞서 <span>“</span>윈도우 프로젝트 필수 유틸리티<span>”</span>의 한 대목에서 소개한 문제도 발생하지 않는다<span>.</span></p>
<p>&nbsp;</p>
<p><span>CCNET</span>에는 <span>MSBuild</span>용 로거가 있다<span>.</span> 이 로거는 <span>MSBuild</span> 스크립트에서 <span>&lt;msbuild&gt;</span> 태스크를 사용하여 솔루션 파일을 빌드할 때 가장 잘 작동한다<span>.</span> 하지만 다행스럽게도 <span>&lt;Exec&gt;</span> 태스크를 사용해도 이 로거는 작동한다<span>.</span> 단지<span>,</span> 로그 상세 정도를 지정하는 옵션<span>(Verbose)</span>은 제대로 동작하지 않기 때문에<span>,</span> 웹 대시보드에서 표시되는 로그가 상당히 길어지기 마련이다<span>.</span> 하지만 빌드가 깨졌을 때만 웹 대시보드에 들리게 되니 마우스 스크롤의 불편함 정도는 감수할만하다<span>.</span></p>
<p>&nbsp;</p>
<h3><span>64</span>비트로 빌드하기</h3>
<p class="MsoNormal">이제 <span>MSBuild</span>를 활용해 <span>64</span>비트 <span>Visual C++</span> 프로젝트를 빌드해보자<span>. x64</span> 빌드를 잘 다룰 수 있다면 <span>WIN32</span> 빌드는 쉽다<span>.</span> 사실 우리는 <span>32</span>비트 환경에 익숙하기 때문에 <span>32</span>비트 빌드 자동화는 크게 문제되지 않는다<span>.</span> 문제는 <span>x64</span> 빌드인데<span>,</span> 익숙하지 않은 환경일뿐더러 <span>64</span>비트 <span>WOW</span> 환경에선 <span>32</span>비트 에뮬레이션이 가능하므로 헷갈릴만한 요소가 많다<span>.</span> 그러니 <span>64</span>비트 빌드 자동화부터 익숙해져 보자<span>.</span></p>
<p>&nbsp;</p>
<h4>왜 <span>64</span>비트 <span>MSBuild</span>인가<span>?</span></h4>
<p><span>64</span>비트 운영체제엔 두 개의 <span>MSBuild</span>가 있다<span>. C:WINDOWSMicrosoft.NETFrameworkv2.0.50727msbuild.exe</span>와 <span>C:WINDOWSMicrosoft.NETFramework64v2.0.50727msbuild.exe</span>인데<span>,</span> 자세히 보면 <span>64</span>란 숫자가 붙어있다<span>.</span> 한 마디로 말해 <span>32</span>비트용<span>MSBuild</span>이냐<span>, 64</span>비트용 <span>MSBuild</span>이냐라는 차이가 있다<span>.</span></p>
<p>&nbsp;</p>
<p>논의를 좀더 진행하기에 앞서 비주얼 스튜디오 <span>2005</span>를 잠시 살펴보자<span>. Visual Studio 2005 x64</span>란 키워드로 구글링해봐야 <span>64</span>비트용 비주얼 스튜디오를 찾을 수는 없다<span>. 32</span>비트용 비주얼 스튜디오만 있는데<span>, 32</span>비트용이라고 해도 <span>32</span>비트와 <span>64</span>비트 컴파일 모두 지원한다<span>.</span></p>
<p>&nbsp;</p>
<p>이와 마찬가지로 <span>32</span>비트용 <span>MSBuild</span>를 사용해도<span>64</span>비트 <span>VC++</span> 프로젝트를 빌드하는 데 아무런 문제도 없다<span>.</span> 그렇다면 왜 <span>64</span>비트용을 굳이 써야 하는가<span>?</span></p>
<p>&nbsp;</p>
<p><span>32</span>비트용 <span>MSBuild</span>로 <span>64</span>비트 <span>VC</span> 프로젝트와 <span>64</span>비트 <span>.NET</span> 프로젝트를 함께 빌드하려고 하면 문제가 발생한다<span>. VC</span> 프로젝트는 빌드가 되지만<span>,</span> 닷넷 프로젝트는 빌드가 안 된다<span>.</span> 곰곰이 생각해보면 뭔가 이상하다<span>. 32</span>비트용인 비주얼 스튜디오로 <span>64</span>비트 닷넷 프로젝트를 빌드할 수 있는데<span>, MSBuild</span>만 왜 난리를 치는가<span>?</span> 고민해봤지만 결국 원인을 파악하지 못했다<span>.</span> 환경 설정을 바꿔가며 테스트해봤지만 결과는 같았다<span>.</span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><strong style="">결론<span>1.</span></strong> <span>64</span>비트 빌드를 하려면 <span>64</span>비트 <span>MSBuild</span>를 사용하라<span>.</span></p>
<p>&nbsp;</p>
<p class="MsoNormal">&nbsp;</p>
<h4><span>64</span>비트 <span>MSBuild</span>에 문제는 없는가<span>?</span></h4>
<p class="MsoNormal"><span>64</span>비트용 <span>MSBuild</span>로 <span>VC</span> 프로젝트를 빌드하다가 괴상한 오류와 마주쳤다<span>.</span></p>
<p>&nbsp;</p>
<ol class="code">
<li>
<p class="MsoNormal">C2259: "cannot instantiate abstract class"</p>
</li>
</ol>
<p>&nbsp;</p>
<p class="MsoNormal">이 오류는 <span>Visual Studio 2005</span>의 버그였는데<span>1,</span> 서비스 팩 <span>1</span>에서 고쳐졌다<span>.</span> 하지만 <span>64</span>비트용 <span>vcbuild.exe</span>는 깜박 잊고 손보지 않았는지<span>,</span> 이 오류 메시지가 출력됐다<span>.</span> 역시나 환경 설정을 잘못했나 살펴봤지만<span>,</span> 그다지 이상한 점이 눈에 띄지는 않았다<span>.</span></p>
<p>&nbsp;</p>
<p>다행히 이 오류는 컴파일러 파서가 삽질할 때 나기 때문에 원래 소스 코드에 의미상 아무런 차이도 없는 캐스팅을 붙여줌으로써 문제를 해결했다<span>.</span> 물론 <span>32</span>비트 빌드할 때와 <span>64</span>비트 빌드할 때<span>,</span> 서로 다른 버전의 컴파일러를 쓴다는 점이 마음에 걸리긴 한다<span>.</span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><strong style="">결론 <span>2</span></strong><span>. 32</span>비트 <span>vcbuild.exe</span>에 적용된 핫픽스가 <span>64</span>비트 <span>vcbuild</span>에는 적용 안 됐다<span>.</span></p>
<p>&nbsp;</p>
<h4>환경 설정 불러내기</h4>
<p class="MsoNormal">비주얼 스튜디오 <span>2005</span>가 깔려 있다고 가정하고 이야기를 진행하자<span>.</span> 보통 <span>32</span>비트 빌드를 할 때는 이런 식으로 배치 파일을 만든다<span>.</span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><strong style=""><span>[</span>목록 <span>3] msbuild-win32.bat</span></strong></p>
<ol class="code">
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">call "&#xVS;80COMNTOOLS%"vsvars32.bat</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">msbuild buildall.msbuild /t:Build</span></p>
</li>
</ol>
<p>&nbsp;</p>
<p class="MsoNormal"><span>64</span>비트 빌드할 때는 이렇게 하면 된다<span>.</span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><strong style=""><span>[</span>목록 <span>3] msbuild-x64.bat</span></strong></p>
<ol class="code">
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">@echo off</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">call "C:Program Files (x86)Microsoft Visual Studio 8VCvcvarsall.bat" x64</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">call "C:Program FilesMicrosoft.NETSDKv2.0 64bitBinsdkvars.bat"</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">"C:WINDOWSMicrosoft.NETFramework64v2.0.50727msbuild.exe" /t:Build</span></p>
</li>
</ol>
<p>&nbsp;</p>
<h4><span>CruiseControl .NET</span> 연동하기</h4>
<p class="MsoNormal"><strong style=""><span style="font-size: 8pt;">[</span></strong><strong style=""><span style="font-size: 8pt;">목록</span> 4] CCNet.config</strong>의 <span>MSBuild</span> 태스크</p>
<ol class="code">
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;msbuild&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;executable&gt;C:WINDOWSMicrosoft.NETFramework64v2.0.50727msbuild.exe&lt;/executable&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;workingDirectory&gt;C:srcsrc&lt;/workingDirectory&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;projectFile&gt;build.msbuild&lt;/projectFile&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;buildArgs&gt;/noconsolelogger /p:Configuration=Debug /v:m&lt;/buildArgs&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;targets&gt;Build&lt;/targets&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;timeout&gt;12000&lt;/timeout&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;logger&gt;C:Program Files (x86)CruiseControl.NETserverThoughtWorks.CruiseControl.MSBuild.dll&lt;/logger&gt;</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;/msbuild&gt;</span></p>
</li>
</ol>
<p>&nbsp;</p>
<p class="MsoNormal">일반적인 <span>CCNet.config</span> 설정은 위와 같다<span>.</span> 하지만 환경 설정 값을 불러내야 하기 때문에 곧바로 <span>msbuild.exe</span>를 호출해선 안 된다<span>.</span> 우선 <span>MsBuild_x64_ForCI.bat</span> 란 배치 파일을 만든다<span>.</span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><strong style=""><span>[</span>목록 <span>5] MsBuild_x64_ForCI.bat</span></strong></p>
<ol class="code">
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">@echo off</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">call "C:Program Files (x86)Microsoft Visual Studio 8VCvcvarsall.bat" x64</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">call "C:Program FilesMicrosoft.NETSDKv2.0 64bitBinsdkvars.bat" &gt;&gt;</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">"C:WINDOWSMicrosoft.NETFramework64v2.0.50727msbuild.exe" %*</span></p>
</li>
</ol>
<p>&nbsp;</p>
<p class="MsoNormal">그러고 나서 <span>CCNet.config</span> 파일을 수정해주면 된다<span>.</span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><strong style=""><span style="font-size: 8pt;">[</span></strong><strong style=""><span style="font-size: 8pt;">목록</span> 6]</strong> 올바른 <span>CCNet.config</span> 설정</p>
<ol class="code">
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;msbuild&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;executable&gt;MsBuild_x64_ForCI.bat&lt;/executable&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;workingDirectory&gt;C:srcsrc&lt;/workingDirectory&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;projectFile&gt;build.msbuild&lt;/projectFile&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;buildArgs&gt;/noconsolelogger /p:Configuration=Debug /v:m&lt;/buildArgs&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;targets&gt;Build&lt;/targets&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;timeout&gt;12000&lt;/timeout&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;logger&gt;C:Program Files (x86)CruiseControl.NETserverThoughtWorks.CruiseControl.MSBuild.dll&lt;/logger&gt;</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;/msbuild&gt;</span></p>
</li>
</ol>
<p>&nbsp;</p>
<h4>개선하기</h4>
<p class="MsoNormal">여기서 모든 게 끝났다고 생각하면 오산이다<span>. CruiseControl .NET</span> 빌드 파일을 보면 뭐가 문제인지 알 수 있다<span>.</span></p>
<p>&nbsp;</p>
<ol class="code">
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;cruisecontrol&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">&lt;msbuild startTime="10/30/2007 16:43:39" elapsedTime="00:00:12" success="true"&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">&lt;project name="Build" file="C:srcbuild.msbuild" success="true"&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">&lt;project name="Rebuild" file="C:srcProjects.sln" success="true"&gt;</span></p>
</li>
<li>
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">&lt;message level="high"&gt;&lt;![CDATA[MockClientForMaster -&gt; C:srccuckoo-x64-releaseserversrcTestServicesMockClientForMasterbinx64ReleaseMockClientForMaster.exe]]&gt;&lt;/message&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal" style="margin-left: 2em;"><span style="font-size: 8pt;">&lt;/project&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;/project&gt;</span></p>
</li>
<li style="margin-left: 2em;">
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;/msbuild&gt;Setting environment for using Microsoft Visual Studio 2005 x64 tools.</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">Setting environment to use Microsoft .NET Framework v2.0 SDK tools.</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">For a list of SDK tools, see the 'StartTools.htm' file in the bin folder.</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">&lt;/cruisecontrol&gt;</span></p>
</li>
</ol>
<p>&nbsp;</p>
<p class="MsoNormal">환경 설정을 불러내면서 콘솔에 메시지가 출력되는 바람에 <span>CCNet</span> 로그가 엉망이 되어 버렸다<span>.</span> 이 문제는<span>MsBuild_x64_ForCI.bat</span> 배치 파일을 조금만 손보면 해결할 수 있다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<ol class="code">
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">@echo off</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">call "C:Program Files (x86)Microsoft Visual Studio 8VCvcvarsall.bat" x64</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">&gt; _temp.txt</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">call "C:Program FilesMicrosoft.NETSDKv2.0 64bitBinsdkvars.bat" &gt;&gt; _temp.txt</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">"C:WINDOWSMicrosoft.NETFramework64v2.0.50727msbuild.exe" %*</span></p>
</li>
</ol>
<p>&nbsp;</p>
<p class="MsoNormal">콘솔 출력을 텍스트 파일로 리다이렉트시켰다<span>.</span> 이로써 모든 게 끝났다<span>.</span></p>
<p>&nbsp;</p>
<h3>추천 문서</h3>
<ul>
<li>MSBuild라는 키워드로 MSDN 라이브러리를 뒤적이면 MSBuild를 이해하는 데 큰 도움이 된다.</li>
<li>MSDN 라이브러리를 읽고 MSBuild의 개념이나 작동 방식을 이해했다면, Guy Smith-Ferrier(<a href="http://www.guysmithferrier.com/" class="external" title="http://www.guysmithferrier.com/">http://www.guysmithferrier.com/</a>)가 쓴 Automating Builds Using MSBuild(<a href="http://www.guysmithferrier.com/downloads/msbuild.pdf" class="external" title="http://www.guysmithferrier.com/downloads/msbuild.pdf">http://www.guysmithferrier.com/downloads/msbuild.pdf</a>)를 옆에 두고 레퍼런스로 쓰면 좋다.</li>
<li>MSBuild 관련 자료 중의 역시 최고라 하면 Part 1: Continuous Integration using MSBuild, CruiseControl.NET, FxCop, NUnit, NCover + Subversion(<a href="http://dotnet.org.za/cjlotz/archive/2007/04/04/part-1-continuous-integration-using-msbuild-cruisecontrol-net-fxcop-nunit-ncover-subversion.aspx" class="external" title="http://dotnet.org.za/cjlotz/archive/2007/04/04/part-1-continuous-integration-using-msbuild-cruisecontrol-net-fxcop-nunit-ncover-subversion.aspx">http://dotnet.org.za/cjlotz/archive/2007/04/04/part-1-continuous-integration-using-msbuild-cruisecontrol-net-fxcop-nunit-ncover-subversion.aspx</a>)을 비롯한 6편짜리 글일 것이다. MSBuild와 CruiseControl .NET 그리고 Subversion은 지금으로선 가장 유망한 조합이 아닐까? Microsoft사의 솔루션을 몽땅 구매해도 괜찮을 정도의 조직이라면 몰라도 말이다. C# 개발 그룹이라면 그대로 따라하면 될 것이고, VC++ 개발 팀이라면 약간 응용력을 발휘해야 한다.</li>
</ul>
<p class="MsoNormal">&nbsp;</p>
<p>&nbsp;</p>
<h3>추천 도구</h3>
<h4><span>MSBuildTasks</span></h4>
<p class="MsoNormal"><span>MSBuildTasks(<a href="http://msbuildtasks.tigris.org/">http://msbuildtasks.tigris.org/</a>)</span>는 <span>MSBuild</span>의 확장팩이라고 생각하면 된다<span>.</span> 스타크래프트 브루드워 같은 것이랄까<span>?</span> 주요 기능을 살펴보면 간략하게 이렇다<span>.</span></p>
<p>&nbsp;</p>
<ul>
<li>레지스트리 조작 (RegistryRead, RegistryWrite)</li>
<li>C# 스크립트 실행 (Script)</li>
<li>파일 업로드 (FileUpdate, FtpUpload)</li>
<li>SQL 실행 (ExecuteDDL)</li>
<li>이메일 전송 (Mail)</li>
<li>NDoc 및 NUnit 지원</li>
<li>정규표현식 (RegexMatch, RegexReplace)</li>
<li>서브버전 및 Visual SourceSafe 제어 (SvnCheckout, SvnClient, SvnCommit 등)</li>
<li>파일 압축 (Unzip, Zip)</li>
<li>XML 읽고 쓰기 (XmlRead, XmlWrite 등)</li>
</ul>
<p>&nbsp;</p>
<p class="MsoNormal">레지스트리 조작과 <span>C#</span> 스크립트 실행 기능은 <span>ODBC DSN</span>을 등록할 때 써보았고<span>, ExecuteDDL</span>은 단위 테스트 전에 데이터베이스 스키마를 생성할 때 썼다<span>.</span> 서브버전 제어 기능을 이용해 특정 소스 코드가 변했을 때만 다시 빌드<span>(Rebuild)</span>를 하는 논리를 구성하기도 했다<span>.</span> 기회가 닿는 대로 이 모든 사례에 대해 알아보도록 하겠다<span>.</span></p>
<p>&nbsp;</p>
<h4><span>MSBuildShellExtension</span></h4>
<p class="MsoNormal"><span>MSBuildShellExtension(<a href="http://www.codeplex.com/msbuildshellex">http://www.codeplex.com/msbuildshellex</a>)</span>는 <span>Visual Studio</span>에서 곧바로 <span>MSBuild</span> 스크립트를 실행시키게 해준다<span>.</span> 스크린 샷을 보면 어떤 도구인지 한눈에 알 수 있다<span>.</span></p>
<p class="MsoNormal">&nbsp;<img title="MSBuildShellExtension.png" class="attachment" src="http://kaistizen.springnote.com/pages/2181444/attachments/986250" alt="MSBuildShellExtension.png" /></p>
<p class="MsoNormal"><span>Visual Studio</span>가 제공하는 빌드 이벤트 같은 것에 의존하지 않으려면 이것도 좋다<span>.</span></p>
<p>&nbsp;</p>
<h3>끝마치는 말</h3>
<p class="MsoNormal">이번 시간엔 <span>64</span>비트 빌드 자동화의 기본을 익혔다<span>.</span> 이제부턴 응용만 남았다<span>.</span> 응용은 어려워 보여도 실은 기초가 갖춰지면 응용은 아무것도 아니다<span>.</span> 하지만 <span>‘</span>아<span>,</span> 이런 것도 가능하구나<span>’</span>라는 가능성을 보면 빌드 스크립트의 도입을 설득하고 추진하기 쉬워질 것이다<span>.</span></p>
<p>&nbsp;</p>
<p class="MsoNormal">&nbsp;</p>
<p>&nbsp;</p>
<p style="text-align:right">이 글은 <a href="http://kaistizen.springnote.com/pages/2181444">스프링노트</a>에서 작성되었습니다.</p>
												
				<br/>
				
<p><a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/80x15.png" /></a><br/>
이 저작물은 <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/">크리에이티브 커먼즈 코리아 저작자표시-동일조건변경허락 2.0 대한민국 라이센스</a>에 따라 이용하실 수 있습니다.</p>

			</div>
		</content>
	</entry>

	<entry>
		<title>실전! 지속적인 통합 8편</title>
				<link rel="alternate" type="text/html" href="http://kaistizen.net/EE/index.php/imaso/continuousintegration_2008_08/" />
				
		<id>tag:kaistizen.net,2008:EE/index.php/weblog/index/2.1439</id>
		<published>2008-11-29T15:14:00Z</published>
		<updated>2008-11-29T16:43:42Z</updated>
		<author>
			<name>최재훈</name>
			<email>kaistizen@gmail.com</email>
			<uri>http://kaistizen.net</uri>		</author>

		<category term="소프트웨어 개발" scheme="http://kaistizen.net/EE/index.php/weblog/C17/" label="소프트웨어 개발" />

		<category term="프로젝트" scheme="http://kaistizen.net/EE/index.php/weblog/C12/" label="프로젝트" />
 
		<category term="마이크로소프트웨어" scheme="http://kaistizen.net/EE/index.php/weblog/" label="마이크로소프트웨어" />
 
		<category term="지속적인+통합" scheme="http://kaistizen.net/EE/index.php/weblog/" label="지속적인+통합" />

		<content type="xhtml">
			<div xmlns="http://www.w3.org/1999/xhtml">

								

					<h3 class="MsoNormal"><strong style="">단위 테스트 <span>3</span>편 <span>–</span> 단위 테스트 코드 짜보기</strong></h3>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal">지속적인 통합은 단순히 생각하면 빌드 자동화<span>,</span> 컴파일 자동화에 불과하다<span>.</span> 자동화 자체를 꾀하는 개발팀이 의외로 적다는 점을 감안하면 <span>‘</span>불과하다<span>’</span>고 폄하할 필요는 없지만<span>,</span> 더 많은 가능성이 있는데 이를 전부 활용하지 못하니 아쉬울 뿐이다<span>.</span> 지속적인 컴파일을 넘어 소프트웨어 코드베이스의 품질을 극적으로 개선하는 방법이 있는데<span>,</span> 이를 활용하지 못하는 현실이 안타깝다<span>.</span> 개발자 테스트<span>(</span>단위 테스트 등<span>)</span>는 도입하기 쉽지 않지만<span>,</span> 느긋하게 마음 먹고 익숙해지면 많은 게 변한다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<div class="section" style="background-color: rgb(249, 249, 216);">
<p class="MsoNormal"><strong style=""><span>[</span>필자 소개<span>]</span> 최재훈</strong> <span><a href="http://kaistizen.net/">http://kaistizen.net</a>, <a href="http://kaistizen.springnote.com/pages/mailto:kaistizen@gmail.com">kaistizen@gmail.com</a> SK</span> 아이미디어의 게임 서버 팀에서 일한다<span>.</span> 요즘은 스크립트 엔진을 개발하는 데 전념하며<span>,</span> 새로운 도전을 즐긴다<span>.</span> 직업 외적인 측면에선 배철수의 음악 캠프를 <span>15</span>년째 즐겨 듣고<span>, U2</span>가 최고의 밴드라 생각한다<span>.</span></p>
</div>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal">이번 칼럼이 단위 테스트를 다룬 세 번째 글이다<span>.</span> 여느 때와 마찬가지로 복습을 잊지 말자<span>.</span> 단위 테스트 첫 편에선 단위 테스트가 왜 중요한지<span>,</span> 어떤 단위 테스트 라이브러리를 골라야 하는지 알아봤다<span>.</span> 닷넷에선 <span>64</span>비트 환경을 지원하는 <span>NUnit</span>을 추천했으며<span>, C++</span>이나 <span>C++/CLI</span> 환경이라면 예외 처리가 잘 되고 <span>XML</span> 출력이 가능해 <span>CruiseControl .NET</span>과 연동하기 쉬운 <span>UnitTest++</span>을 권했다<span>.</span></p>
<p class="MsoNormal">두 번째 칼럼에선 <span>UnitTest++</span>과 <span>CruiseControl .NET</span>을 연동해봤다<span>.</span> 개발자가 테스트할 땐 표준 입출력에 결과를 출력하고<span>,</span> 빌드 서버가 테스트를 돌릴 땐 파일에 <span>XML</span> 형식의 결과값을 기록한다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10pt;">테스트 코드에 표준입출력을 사용하는 코드가 있으면 <span>CruiseControl .NET</span>의 빌드 로그가 망가질 수 있으니<span>, UnitTestExec.bat</span>란 배치 파일을 만들어 이런 문제를 방지했다<span>.</span> 다음 칼럼부터 다룰<span>MSBuild</span>의 경우에도 이렇게 배치 파일을 적극적으로 활용하게 된다<span>.</span> 꽤 유용한 기법이니 어렵지 않다고 대충 넘기지 말고 새겨두면 좋다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10pt;">두 칼럼에서 가장 중요한 내용은 역시 <span>UnitTest++</span>의 테스트 결과 보고서를 웹 대시보드를 통해 깔끔하게 정리해 보여주는 기법이다<span>. CruiseControl .NET</span>이 <span>UnitTest++</span>을 공식적으로 지원하지 않기 때문에 직접 <span>Unittests.xsl</span> 파일을 편집했다<span>.</span> 개발팀마다 프로젝트마다 빌드 환경이 달라지기 때문에 이렇게 사람의 손길이 닿아야 할 일이 생긴다<span>.</span> 이번처럼 누군가 칼럼이나 웹 페이지를 통해 해결책을 공개한 경우라면 운이 좋은 것이지만<span>,</span> 항상 이렇게 일이 잘 풀리진 않으니 <span>CruiseControl .NET</span>의 동작 원리를 잘 알아두면 좋다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10pt;">자<span>,</span> 복습은 끝났다<span>.</span> 이제 본론<span>,</span> 즉 단위 테스트를 어떻게 도입하고 활용할 것인지에 대해 알아보자<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10pt;">&nbsp;</p>
<h3>프로젝트 구성하기</h3>
<p class="MsoNormal">거듭 말하지만 이 칼럼은 <span>Visual C++</span>을 기준 삼는다<span>. VC++</span> 프로젝트의 구성 유형은 크게 세 가지다<span>.</span> 응용프로그램<span>(.exe),</span> 동적 라이브러리<span>(.dll),</span> 정적 라이브러리<span>(.lib)</span> 말이다<span>.</span> 각각의 프로젝트마다 그에 해당하는 <span>UnitTest++</span> 프로젝트를 구성하는 방법이 다르다<span>.</span> 이제부터 하나씩 알아보자<span>.</span><img alt="" /></p>
<p class="MsoNormal">&nbsp;<img alt="" /><img alt="" /><img alt="" /></p>
<h4>정적 라이브러리<img alt="" /></h4>
<p class="MsoNormal" style=""><span style=""><img height="244" width="264" /></span></p>
<p class="MsoCaption"><strong>그림 <span><span style="">1</span></span><span>.</span></strong>정적 라이브러리에 대한 종속성</p>
<p class="MsoCaption"><img class="attachment" title="그림_1._정적_라이브러리에_대한_종속성.png" src="http://kaistizen.springnote.com/pages/2180976/attachments/986164" height="399" alt="그림_1._정적_라이브러리에_대한_종속성.png" width="432" /></p>
<p class="MsoCaption">&nbsp;</p>
<p class="MsoNormal"><img alt="" /><img alt="" /><img alt="" /><img alt="" /><img alt="" /><img alt="" /><img alt="" /></p>
<p class="MsoNormal">우선 <span>[</span>그림 <span>1]</span>을 보자<span>.</span> 여기서 <span>Core</span>는 정적 라이브러리고<span>, CuckooTest</span>는 <span>Core</span>에 대한 단위 테스트 프로젝트다<span>.</span> 물론 <span>CuckooTest</span>는 콘솔 애플리케이션이다<span>.</span> 이 그림에서 <span>CuckooTest</span>는<span>Core</span>에 대한 종속성이 있다<span>.</span> 이렇게 프로젝트 종속성을 설정해놓으면 <span>CuckooTest</span>를 빌드할 때 <span>Core.lib</span> 파일을 링크할 때 입력 값으로 쓴다<span>.</span> 물론 이 말엔 전제가 있다<span>. CuckooTest</span> 프로젝트 구성 값이 <span>[</span>그림 <span>2]</span>와 같아야 한다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal" style=""><span style=""><img height="248" width="321" /></span></p>
<p class="MsoCaption"><strong>그림 <span><span style="">2</span></span></strong><span><strong>.</strong> CuckooTest</span> 프로젝트</p>
<p class="MsoNormal">&nbsp;<img class="attachment" title="그림_2._CuckooTest_프로젝트.png" src="http://kaistizen.springnote.com/pages/2180976/attachments/986162" height="462" alt="그림_2._CuckooTest_프로젝트.png" width="600" /></p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal"><span>“</span>프로젝트 의존성 링크하기<span>(Link Project Dependencies)”</span>를 선택해야 이렇게 알아서 <span>Core.lib</span>을 링크한다<span>.</span> 하지만 프로젝트를 처음 만들 때 이 값이 기본적으로 선택되므로 신경 쓸 일이 거의 없다<span>.</span></p>
<p class="MsoNormal">이게 전부다<span>.</span> 나머진 <span>UnitTest++</span> 홈페이지에 있는 <span>“Step, a step by step example”(<a href="http://unittest-cpp.sourceforge.net/money_tutorial/">http://unittest-cpp.sourceforge.net/money_tutorial/</a>)</span> 문서를 따라 하면 끝이다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<h4>동적 라이브러리</h4>
<p class="MsoNormal">실은 동적 라이브러리를 직접 개발해 쓴 적이 없다<span>.</span> 아니<span>,</span> 그런 적이 있긴 하지만 직접 짠 라이브러리가 아니었고<span>,</span> 그 코드에 대해 단위 테스트를 해본 적이 없다는 게 정확하다<span>.</span> 그렇다면 동적 라이브러리인 경우는 설명할 능력이 없느냐<span>?</span> 또는 설명할 자격이 없느냐<span>?</span></p>
<p class="MsoNormal" style="text-indent: 10pt;">그렇기도 하고 아니기도 한다<span>.</span> 일반적인 동적 라이브러리에 대한 경험은 부족하지만<span>, C++/CLI</span>를 다룬 경험이 있다<span>.</span> 네이티브 코드<span>(</span>일반적인 <span>C++)</span>에 대한 관리되는 래퍼 라이브러리<span>(</span>간단히 말해 닷넷 기능이 들어간 <span>C++</span> 코드<span>)</span>를 짠 경험은 풍부하다<span>.</span> 보통 <span>C++/CLI</span> 라이브러리는 동적 라이브러리의 형태를 띈다<span>.</span> 만약 정적 라이브러리로 빌드해 버리면<span>,</span> 외부의 관리되는 코드<span>(C#</span>이든 <span>C++/CLI</span>든<span>)</span>가 해당 라이브러리에 어떤 타입이 있는지 알 수 없게 되기 때문이다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10pt;">동적 라이브러리를 쓰면 외부에 공개된 인터페이스만 접근할 수 있다<span>.</span> 이는 단위 테스트도 마찬가지라 상당수의 코드를 테스트하지 못한다<span>.</span> 하지만 동적 라이브러리의 오브젝트 파일을 직접 링크하면 문제는 쉽게 해결된다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10.5pt;"><span>[</span>그림 <span>3]</span>을 보자<span>. ScriptShell</span>이란 동적 라이브러리가 있고<span>, ScriptShellTest</span>란 단위 테스트 프로젝트가 있다<span>.</span> 이때 단위 테스트 프로젝트의 구성 값 중 <span>“</span>추가 의존성<span>”</span>란이 핵심이다<span>.</span> 링크시<span>ScriptShell</span>의 모든 오브젝트 파일을 입력 값으로 쓰라고 해놨다<span>.</span> 이렇게만 하면 된다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10.5pt;">단<span>,</span> 이런 식으로 오브젝트 파일을 직접 링크하면 빌드 시간이 꽤 늘어난다<span>.</span> 사실<span>,</span> 사람들이 단위 테스트를 자주 실행하게 만들려면<span>,</span> 단위 테스트를 빌드하고 실행하는 데 걸리는 시간이 짧아야 하기 때문에 이는 문제의 소지가 있다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10.5pt;">&nbsp;</p>
<p class="MsoNormal" style=""><span style=""><img height="245" width="316" /></span></p>
<p class="MsoCaption"><strong>그림 <span><span style="">3</span></span><span>.</span></strong>외부 의존성 추가하기</p>
<p class="MsoNormal">&nbsp;<img class="attachment" title="그림_3._외부_의존성_추가하기.png" src="http://kaistizen.springnote.com/pages/2180976/attachments/986166" height="466" alt="그림_3._외부_의존성_추가하기.png" width="600" /></p>
<h4>응용프로그램</h4>
<p class="MsoNormal">응용프로그램도 동적 라이브러리와 마찬가지로 <span>“</span>추가 종속성<span>”</span> 기능을 활용하면 된다<span>.</span> 하지만 더 좋은 방법은 프로젝트 구성 자체를 바꾸는 것이다<span>.</span> 약간만 수고하면 오브젝트 파일을 링크하는 데 소모되는 엄청난 시간을 아낄 수 있다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10pt;">보통 응용프로그램 프로젝트를 만들고 그 안에 소스 코드를 마구 추가해 넣기 시작한다<span>.</span> 하지만 방법을 달리하면 어떨까<span>?</span> 기존 응용프로그램 프로젝트를 정적 라이브러리로 바꾸고<span>,</span> 응용프로그램 프로젝트를 새로 추가한다<span>.</span> 그리고 새로 만든 응용프로그램 프로젝트엔 프로그램을 시작시키는 메인 함수만 둔다<span>.</span> 이렇게 하면 단위 테스트 프로젝트가 정적 라이브러리를 직접 참조해 쓸 수 있다<span>.</span> 당연히 빌드 시간도 줄어든다<span>.</span> 아주 조금 수고할 의욕만 있으면 된다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal">&nbsp;</p>
<h3>테스트의 어려움</h3>
<p class="MsoNormal">테스트 주도 개발이란 말을 많이 들어봤을 것이다<span>.</span> 코드를 먼저 짜고 테스트하는 게 일반적인 개발 순서라면<span>,</span> 테스트 주도 개발은 이와 반대로 운용된다<span>.</span> 간단히 말해 테스트 코드부터 짜고 실제 기능 구현이 이어진다<span>.</span> 이렇게 하면 코드의 추상화나 사용편의성을 좀더 생각하게 되고<span>,</span> 자연히 코드 품질이 향상된다는 이야기다<span>.</span> 하지만 테스트 주도 개발을 하는 개발자나 조직은 보기 힘들다<span>.</span> 왜 그럴까<span>?</span></p>
<p class="MsoNormal" style="text-indent: 10.5pt;">처음 테스트 주도 개발을 접하고 단위 테스트를 도입할 때였다<span>.</span> 학교를 벗어나 현업을 처음 접할 무렵의 일이다<span>.</span> 테스트 주도 개발을 도입하면 전문가답게 일하는 모양새가 날 거라 생각해서 <span>NUnit</span>을 설치하고 사용법을 알아봤다<span>(C#</span>을 다뤘다<span>).</span> 그리고 책에서 봤던 대로 테스트부터 짜려 했다<span>.</span> 그런데 잘 됐을까<span>?</span> 전혀 그렇지 않았다<span>.</span> 하루가 채 지나기도 전에 포기하고 말았다<span>.</span> 테스트 주도 개발을 직접 해보면 알겠지만<span>,</span> 이것은 상당히 극단적인<span>(extreme)</span> 기법이다<span>.</span> 실제 코드의 인터페이스가 어때야 할지<span>,</span> 사용자는 어떤 식으로 코드를 쓰려 들 것인지 판단하기가 쉽지 않다<span>.</span> 이런 판단을 금새 해내려면<span>,</span> 프로그래밍 언어<span>(</span>이 경우엔 <span>C#)</span>를 잘 아는 정도론 안 된다<span>.</span> 디자인 패턴 등을 익히고 설계 경험을 쌓은 후에야 가능하다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10.5pt;">테스트 주도 개발은 어렵다<span>.</span> 하지만 좌절할 일은 아니다<span>.</span> 테스트가 쉽다면 품질보증 팀이나 테스트 전문가의 존재 이유가 없지 않겠는가<span>?</span> 그러니 실망하지 말고 쉬운 일부터 하나씩 해나가자<span>.</span> 우선 다음의 <span>“</span>단위 테스트의 일상화<span>”</span>에서 제시하는 내용부터 실천해보자<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal">&nbsp;</p>
<h3>단위 테스트의 일상화</h3>
<p class="MsoNormal">개발을 혼자 하면 편할지 모른다<span>.</span> 내가 의지만 있으면 빌드 서버를 도입하고 테스트 주도 개발을 할 수 있다<span>.</span> 하지만 학교 숙제가 아니고선 혼자 개발하는 일은 거의 없다<span>.</span> 조언을 얻을 사람이 생긴다는 장점이 있지만<span>,</span> 아무래도 뭔가 도입하고 시도해보긴 어려워진다<span>.</span> 개발자마다 성향이 무척 달라서 버전관리시스템조차 통제의 수단이라며 반발하는 경우가 적지 않다<span>.</span> 사정이 이렇다 보니 단위 테스트를 도입하기도 쉽지 않다<span>.</span> 강제하지 않으면 일년 내내 단위 테스트를 하나도 안 짜는 사람이 속출할 테고<span>,</span> 그렇다고 강제하자니 그것도 문제다<span>.</span> 예를 들어<span>,</span> 테스트 코드가 없는 클래스를 짜면 인사 평가에 반영하겠다고 해보자<span>.</span> 이러면 사람들이 열심히 테스트 코드를 짤까<span>?</span> 십중팔구 사람들은 회피 기술을 찾아낸다<span>.</span> 클래스가 많아질수록 귀찮은 일감이 늘어나니 아예 클래스를 안 만들기로 한다<span>.</span> 곧 몇 천 줄짜리 대형 클래스가 난무하게 된다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10.5pt;">이것은 누굴 비난할 일이 아니다<span>.</span> 중요하다고 생각하지 않는 일에 시간을 투자할 사람은 없다<span>.</span> 단위 테스트를 도입하려면 먼저 구성원들의 공감대를 이끌어내야 한다<span>.</span> 이는 팀장이나 관리자의 영역이다<span>.</span> 아무래도 일개 개발자로선 한계가 있다<span>.</span> 특히 관리자가 회의적일 땐 말이다<span>.</span> 그래서 이 방면에 대핸 더 언급하지 않겠다<span>.</span> 단<span>,</span> 관리자와 팀 구성원들의 공감대가 어느 정도 형성됐다면<span>,</span> 서두르지 말고 하나씩 실행해나가자<span>.</span> 이를테면<span>,</span> 하루에 단위 테스트를 하나만 짜보는 정책은 어떨까<span>?</span> 이 정도면 그리 힘들지 않을 것이다<span>.</span> 그리고 단위 테스트를 꼭 어렵게만 생각할 필요도 없다<span>.</span> 프로그래밍 언어에 대해 궁금한 것이 생겼을 때 활용해도 좋다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10.5pt;">&nbsp;</p>
<p class="MsoNormal"><strong><span>[</span>목록 <span>1]</span></strong>단위 테스트의 일상화</p>
<ol class="code">
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">enum ACCOUNT_GENDER</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">{</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">AG_MALE= 1,//!&lt; Male</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">AG_FEMALE= 2,//!&lt; Female</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">AG_NOTDEFINED= 3,//!&lt; Not Defined</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">AG_UNKNOWN= 4,//!&lt; Unknown</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">AG_DEFAULT = AG_FEMALE,</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">AG_MAX</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">};</span></p>
</li>
</ol>
<p class="MsoNormal">&nbsp;</p>
<ol class="code">
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">TEST(GenderValues)</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">{</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">DWORD expectedAgMax = AG_UNKNOWN + 1;</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">DWORD agMax = static_cast&lt;DWORD&gt;(AG_MAX);</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">CHECK(agMax == expectedAgMax);</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">}</span></p>
</li>
</ol>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal"><span>[</span>목록 <span>1]</span>은 <span>C++</span>의 <span>enum</span>이 어떤 식으로 처리되는지 궁금해서 짠 테스트 코드다<span>.</span> 원래 <span>AG_MAX</span>의 값이 <span>5</span>가 아닐까 싶었는데<span>,</span> 정작 테스트해보니 <span>6</span>이 나왔다<span>.</span> 이런 식으로 단위 테스트를 여러 방면에 활용할 수 있다는 걸 보여주면 좋다<span>.</span> 특히 초심자일수록 이렇게 간단한 테스트 코드를 메인 함수에 넣고 돌려본다<span>.</span> 그리고 원하는 결과를 알아내면 테스트 코드를 지운다<span>.</span> 하지만 하루가 지나고<span>,</span> 한 달이 지난 후 어느 날 다시 똑 같은 코드를 짜는 일이 비일비재하다<span>.</span> 시간이 지나면 잊어먹기 마련이고<span>,</span> 그렇지 않더라도 또 다른 의문이 들 때가 있다<span>.</span> 똑 같은 일을 여러 번 반복하는 건 <span>DIY(Don’t Repeat Yourself)</span> 원칙에 어긋나는 일이니<span>,</span> 이렇게 단위 테스트를 활용하는 편이 좋다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal">&nbsp;</p>
<h3>예외처리</h3>
<p class="MsoNormal" style=""><span style=""><img height="137" width="419" /></span></p>
<p class="MsoCaption"><strong>그림 <span><span style="">4</span></span><span>.</span></strong>충돌이 났을 때</p>
<p class="MsoNormal">&nbsp;<img class="attachment" title="그림_4._충돌이_났을_때.png" src="http://kaistizen.springnote.com/pages/2180976/attachments/986172" alt="그림_4._충돌이_났을_때.png" /></p>
<p class="MsoNormal">코드에 문제가 있어서 단위 테스트가 실패해도 <span>UnitTest++</span>는 죽지 않는다<span>. UnitTest++</span>는 충돌이 난 코드 영역을 실패처리하고 다음 테스트를 실행한다<span>.</span> 이러한 안전성은 <span>UnitTest++</span>을 돋보이게 하는 장점이다<span>.</span> 하지만 테스트 자동화를 꾀할 땐 좀더 신경 쓸 일이 많다<span>.</span> 예외를 알리는 메시지 박스가 그 중 하나다<span>.</span> 충돌이 나면 보통 <span>[</span>그림 <span>4]</span>와 같은 메시지 박스가 뜬다<span>.</span> 단위 테스트 중에 충돌이 나도 마찬가지다<span>.</span> 차이가 있다면<span>, “Don’t send”</span> 버튼을 클릭했을 때 <span>UnitTest++</span>은 다음 테스트를 실행한다는 점이다<span>.</span> 문제는 <span>“</span>버튼을 클릭했을 때<span>”</span>란 대목이다<span>.</span> 다시 말해<span>,</span> 사람이 버튼을 눌러주지 않으면 다음 테스트가 실행되지 않는다는 말이다<span>.</span> 이런 문제 때문에 실제론 테스트가 실패했어도 그 사실을 모르는 경우가 잦다<span>.</span> 빌드 서버엔 오류 메시지 창이 떠 있고 빌드가 끝나지 않는다<span>.</span> 빌드가 끝나지 않으므로 <span>CruiseControl .NET</span>에 빌드의 성공 여부가 보고되지 않고<span>,</span> 사람들은 이전 빌드의 결과<span>(</span>성공<span>)</span>를 보고 안심하는 것이다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10.5pt;">다행히 이런 문제는 어느 정도 대처 가능하다<span>. CHECK, VERIFY</span> 같은 매크로를 <span>(</span>만들어<span>)</span> 쓰는데<span>,</span> 이때 <span>crash</span> 코드를 이용하곤 한다<span>.</span> 물론 <span>crash</span> 코드가 실행되면 오류 메시지 창이 뜬다<span>. crash</span> 대신 예외를 던진다면 어떨까<span>? UnitTest++</span> 같은 단위 테스트 라이브러리엔 예외를 탐지해 대처하는 기능이 들어있다<span>.</span> 그러니 오류 창이 뜰까 걱정하지 않아도 된다<span>.</span> 물론 단위 테스트 상황이 아니라면 처리되지 않은 예외로 처리되어 종전과 같이 오류 창이 뜰 테니 이 점도 걱정하지 않아도 된다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal"><strong style=""><span>[</span>목록 <span>2]</span></strong> <span>UnitTest++</span>의 예외 매크로</p>
<ol class="code">
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">struct TestException {};</span></p>
</li>
<li>
<p class="MsoNormal"><span style="font-size: 8pt;">CHECK_THROW(throw TestException(), TestException);</span></p>
</li>
</ol>
<p class="MsoNormal" style="text-indent: 9.75pt;">&nbsp;</p>
<p class="MsoNormal">&nbsp;</p>
<h3>멀티 스레드에 대한 단위 테스트</h3>
<p class="MsoNormal">애자일 코리아란 구글 그룹이 있다<span>.</span> 어쩌다 보니 요즘은 활동이 없는데 한때는 이런저런 의견을 활발히 교환하던 곳이다<span>.</span> 한번은 멀티스레드 코드를 어떻게 테스트해야 할까란 이야기가 오갔다<span>.</span> 이는 매우 흥미로운 토론이었는데<span>,</span> 그럴만한 게 멀티스레드 때문에 고생하지 않는 사람이 없기 때문이다<span>.</span> 더군다나 요즘엔 멀티스레드를 넘어 멀티코어<span>,</span> 멀티프로세서 시대가 되었기 때문에 문제가 더욱 심각해졌다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 9.75pt;">이 논의는 다음과 같은 질문으로 시작됐다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal"><strong style=""><span>Multithread</span>에 대한 <span>Unit Test</span>는 불가능할까요<span>?</span> 혹은 가능하더라도 별 효용이 없을까요<span>?</span></strong></p>
<p class="MsoNormal">레이스 컨디션과 같은 문제는 원인 파악이 힘들뿐더러 재현하기도 힘들다<span>.</span> 단위 테스트는 일종의 문제를 재현하는 과정인데<span>,</span> 그래서 이런 문제를 해결하기 위한 특별한 도구가 있다<span>.</span> 이 토론 때 언급된 도구로는 다음과 같은 게 있다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<ul>
<li>
<p class="MsoNormal"><span style="font-family: Wingdings;"><span style="">l</span></span><span>Multithreaded unit testing with ConTest (</span><a href="http://www.ibm.com/developerworks/java/library/j-contest.html)"></a><a href="http://www.ibm.com/developerworks/java/library/j-contest.html">http://www.ibm.com/developerworks/java/library/j-contest.html</a>)</p>
</li>
<li>
<p class="MsoNormal"><span style="font-family: Wingdings;"><span style="">l</span></span><span>GroboUtils (<a href="http://groboutils.sourceforge.net/">http://groboutils.sourceforge.net/</a>)</span></p>
</li>
</ul>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal">하지만 안타깝게도 이런 도구를 도입하기가 쉽지 않다<span>.</span> 도구 자체의 문제라기보단 사람의 문제가 크다<span>. UnitTest++</span> 같은 간단한 도구조차 조직에 도입하기 힘든 판에 멀티스레드를 위한 단위 테스트라니<span>!</span></p>
<p class="MsoNormal">결국 <span>UnitTest++</span> 같이 지금 쓰는 도구를 최대한 이용하는 편이 좋다<span>.</span> 직접 <span>lock</span>이나 크리티컬 섹션 등을 활용해 레이스 컨디션 문제 등을 잡아내는 코드를 만들어야 한다<span>.</span> 결코 쉬운 일은 아니지만 참고할만한 지침은 있다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10.5pt;">&nbsp;</p>
<p class="MsoNormal"><strong style=""><span>xUnit Test Patterns</span> 에도 나오는 것 중에<span>, Humble object</span>라는 것이 있습니다<span>. ‘Test</span>하기 어려운</strong></p>
<p class="MsoNormal"><strong style="">환경적인 부분<span>(thread scheduling)</span>에 관련된 코드는 가급적이면 <span>thin</span>하게 만들어라<span>’</span>라는 것이죠<span>.</span></strong></p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal"><strong style="">참고<span>.</span></strong> <span>Humble Object (<a href="http://xunitpatterns.com/Humble%20Object.html">http://xunitpatterns.com/Humble%20Object.html</a>)</span></p>
<p class="MsoNormal">로직을 테스트하기 쉬운 별도의 컴포넌트로 빼내어 환경과 분리시킨다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal" style=""><span><span style=""><img height="173" width="312" /></span></span></p>
<p class="MsoCaption"><strong>그림 <span><span style="">5</span></span></strong><span><strong>.</strong> Humble Object</span></p>
<p class="MsoNormal">&nbsp;<img class="attachment" title="그림_5._Humble_Object.png" src="http://kaistizen.springnote.com/pages/2180976/attachments/986168" alt="그림_5._Humble_Object.png" /></p>
<p class="MsoNormal" style="text-indent: 10.5pt;">이 토론이 시작된 후 처음 달린 댓글이다<span>.</span> 결국 설계의 문제다<span>.</span> 최대한 싱글스레드 환경인 것처럼 짜고 멀티스레드를 지원하는 부분은 따로 빼낸다<span>.</span> 아마도 가장 본질적인 해결책일 것이다<span>.</span> 일단 인간의 사고능력 자체가 한번에 한가지만 집중하고 부수효과<span>(side-effect)</span>를 고려하지 않는 상황에 적합하기 때문에<span>,</span> 문제를 단순화시켜야 한다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10.5pt;">하지만 원칙적인 이야기는 상황이 급할 땐 적용하기 힘들다<span>.</span> 당장 레이스 컨디션 문제가 발생했는데<span>,</span> 설계를 바꾸라고 해도 난감하다<span>.</span> 정확히 뭐가 잘못됐는지 파악해야 설계를 바꿀 테고<span>,</span> 설사 원인 파악이 끝났다 해도 시급히 해결해야 할 문제라 설계를 바꾸는 건 미뤄야 할지도 모른다<span>.</span> 이런 경우엔 테스트를 대충 짜는 방법이 있다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10.5pt;">이상하게 들릴진 몰라도 <span>“</span>대충<span>”</span> 짜는 게 좋을 때가 있다<span>.</span> 레이스 컨디션 문제가 발생했고 그 문제를 재현할 코드가 필요하다고 해보자<span>.</span> 매번 정확히 문제를 짚어내는 코드를 짜려면 힘들다<span>.</span> 그래서 멀티스레드 프로그래밍이 어려운 것이다<span>.</span> 이럴 땐 확률적으로 접근해보자<span>.</span> 열 번 실행해서 한번 꼴로 실패하는 정도라면 어떨까<span>?</span> 대부분의 상황에선 그 정도면 충분하다<span>.</span> 당장 문제를 재현할 수도 있거니와 나중에 빌드 자동화시 문제를 재현하기에도 충분하다<span>.</span> 어차피 소스 코드를 커밋할 때마다 빌드하고 테스트할 테니<span>,</span> 하루에 열 번 이상 테스트가 실행된다<span>.</span> 그러면 똑 같은 문제가 재발하더라도 그 날 바로 알 수 있다<span>.</span></p>
<p class="MsoNormal" style="text-indent: 10.5pt;">이는 단순한 이론이 아니다<span>.</span> 실제로 내가 속한 개발팀은 이렇게 해서 문제를 짚어내고 풀어내왔다<span>.</span> 코드가 꽤 복잡해 제시하진 않았지만<span>,</span> 두 개의 스레드가 변수 값을 증가시키는 테스트 코드가 있다<span>.</span> 대충 이런 식이다<span>.</span> 초기값이 <span>0</span>인 변수를 <span>1</span>씩 증가시키는데<span>,</span> 각 스레드가 이런 일을 다섯 번 한다<span>.</span> 그러면 최종 값이 <span>10</span>이 나와야 한다<span>.</span> 물론 동기화에 문제가 있더라도 운 좋게 최종 값이 <span>10</span>이 나올 수 있다<span>.</span> 하지만 테스트를 열 번<span>,</span> 스무 번 실행시키면 어떨까<span>?</span> 한번 정도 깨진다면 그걸로 충분하다<span>.</span> 하루나 이틀 안에 문제가 재현될 테니 말이다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<div class="section" style="background-color: rgb(249, 249, 216);">
<h4 class="MsoNormal"><strong style="">부록<span>.</span> 지속적인 통합 팁 <span>– Visual UnitTest++</span></strong></h4>
<p class="MsoNormal"><span>UnitTest++</span>은 기본적으로 콘솔 애플리케이션이다<span>. NUnit</span>처럼 화려한 <span>GUI</span>를 제공하지 않는다<span>.</span> 그런데 여러분은 운이 좋다<span>.</span> 비주얼 스튜디오 애드온이 있기 때문이다<span>.</span> 더군다나 한국인 개발자의 성과물이라 더욱 인상적이다<span>. Visual Studio 2005</span>와 <span>2008</span>을 지원하며<span>, UnitTest++</span> 뿐 아니라 <span>CppUnitLite, BoostTest</span> 등도 지원한다<span>. <a href="http://code.google.com/p/vutpp/">http://code.google.com/p/vutpp/</a></span>에 방문해서 다운로드 받고 자세한 사양을 확인하면 된다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal"><span style=""><img height="160" width="298" /></span></p>
<p class="MsoNormal">&nbsp;<img class="attachment" title="그림_6._Visual_UnitTest++.png" src="http://kaistizen.springnote.com/pages/2180976/attachments/986170" alt="그림_6._Visual_UnitTest++.png" /></p>
</div>
<p class="MsoNormal">&nbsp;</p>
<h3>끝마치는 말</h3>
<p class="MsoNormal">이번 칼럼에선 단위 테스트를 일상화하자고 제안했다<span>.</span> 또한 단위 테스트를 적용하다 겪기 마련인 문제도 하나씩 알아봤다<span>.</span> 이런 정보가 여러분에게 도움이 되길 바란다<span>.</span> 다음 시간부턴 <span>MSBuild</span>를 이용하는 법에 대해 알아보겠다<span>.</span></p>
<p class="MsoNormal">&nbsp;</p>
<p style="text-align:right">이 글은 <a href="http://kaistizen.springnote.com/pages/2180976">스프링노트</a>에서 작성되었습니다.</p>
												
				<br/>
				
<p><a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/80x15.png" /></a><br/>
이 저작물은 <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/">크리에이티브 커먼즈 코리아 저작자표시-동일조건변경허락 2.0 대한민국 라이센스</a>에 따라 이용하실 수 있습니다.</p>

			</div>
		</content>
	</entry>

	<entry>
		<title>똘똘이&#45;스머프의 미투데이 &#45; 2008년 11월 27일</title>
				<link rel="alternate" type="text/html" href="http://kaistizen.net/EE/index.php/weblog/comments/2008_11_27/" />
				
		<id>tag:kaistizen.net,2008:EE/index.php/weblog/index/6.1438</id>
		<published>2008-11-26T19:42:00Z</published>
		<updated>2008-11-29T15:18:47Z</updated>
		<author>
			<name>최재훈</name>
			<email>kaistizen@gmail.com</email>
			<uri>http://kaistizen.net</uri>		</author>


		<content type="xhtml">
			<div xmlns="http://www.w3.org/1999/xhtml">

								

					<div class="me2day_daily_digest">
    <ul> 
      <li>
        리모콘질 하다 우연히 들었는데, 아내가 남편이 바람 피지 못하게 하는 주전략이 살찌우는 거란다. 이성에게 비호감이 되도록 만든다는 건데 아내나 여자친구가 야식을 자꾸 권하면 의심해보자.
        <span class="me2_tags">(연애 결혼 여자)</span>
        <span class="datetime"><a href="http://me2day.net/kaistizen/2008/11/26#18:36:06" rel="bookmark" title="퍼머링크" class="datetime">2008-11-26 18:36:06</a></span>
        
      </li>
      <li>
        히스 레저를 모델 삼은 <a href='http://www.amazon.com/Joker-Brian-Azzarello/dp/1401215815'>The Joker</a>라는 그래픽 노블이 미국에서 잘 나가는데 이번에 교보문고에 들어왔다. 환율 덕분에 무려 3만 3천원!!! 나중에 사야지.
        <span class="me2_tags">(그래픽노블 책 만화 조커 배트맨)</span>
        <span class="datetime"><a href="http://me2day.net/kaistizen/2008/11/26#22:51:26" rel="bookmark" title="퍼머링크" class="datetime">2008-11-26 22:51:26</a></span>
        
      </li>
      <li>
        <a href='http://leaflet.tistory.com/558'>서남표 총장이 있는 한</a> 모교에 기부할 생각은 전혀 없다. 그 돈으로 다른 데나 후원해야지. 학교 있을 때 이래저래 논쟁을 많이 했는데 지지파도 많았다. 그 중 1/3 이상은 다른 사람은 '남'으로만 여기더라. 나완 무관하지. 성적이 그 정도면 네가 공부 안 한거겠지.
        <span class="me2_tags">(KAIST)</span>
        <span class="datetime"><a href="http://me2day.net/kaistizen/2008/11/26#23:21:48" rel="bookmark" title="퍼머링크" class="datetime">2008-11-26 23:21:48</a></span>
        
      </li>
      <li>
        아랫글 이어서 하는 말인데, “건방지다”란 평판을 듣고 자란 나조차 진저리가 나더라. 최소한 난 가식적으로 굴진 않지. 평소엔 선량하고 순진한 듯 보이는 아이들 입에서 나오는 말 한마디 한마디가 어찌나 이기적이던지.
        <span class="me2_tags">(KAIST)</span>
        <span class="datetime"><a href="http://me2day.net/kaistizen/2008/11/26#23:23:58" rel="bookmark" title="퍼머링크" class="datetime">2008-11-26 23:23:58</a></span>
        
      </li>
      <li>
        <a href='http://kaistizen.springnote.com/pages/2166346?edit=1'>불확실성과 화해하는 프로젝트 추정과 계획</a>
        <span class="me2_tags">(me2spring 책 프로젝트관리)</span>
        <span class="datetime"><a href="http://me2day.net/kaistizen/2008/11/27#00:32:22" rel="bookmark" title="퍼머링크" class="datetime">2008-11-27 00:32:22</a></span>
        
      </li>
    </ul>
    <p style="background:url('http://me2day.net/images/me2day_icon.gif') no-repeat right top;padding-right:25px;text-align:right; font-size: 0.9em;">
      이 글은 <a href="http://me2day.net/kaistizen" >똘똘이-스머프</a>님의 
      <a href="http://me2day.net/kaistizen/2008/11/26#18:36:06">2008년 11월 26일</a>에서 
      <a href="http://me2day.net/kaistizen/2008/11/27#00:32:22">2008년 11월 27일</a>까지의 
      미투데이 내용입니다.
    </p>
  </div>



												
				<br/>
				
<p><a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/80x15.png" /></a><br/>
이 저작물은 <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/">크리에이티브 커먼즈 코리아 저작자표시-동일조건변경허락 2.0 대한민국 라이센스</a>에 따라 이용하실 수 있습니다.</p>

			</div>
		</content>
	</entry>

	<entry>
		<title>불확실성과 화해하는 프로젝트 추정과 계획</title>
				<link rel="alternate" type="text/html" href="http://kaistizen.net/EE/index.php/weblog/comments/_api5/" />
				
		<id>tag:kaistizen.net,2008:EE/index.php/weblog/index/1.1437</id>
		<published>2008-11-26T15:32:01Z</published>
		<updated>2008-11-26T16:29:22Z</updated>
		<author>
			<name>최재훈</name>
			<email>kaistizen@gmail.com</email>
			<uri>http://kaistizen.net</uri>		</author>

		<category term="재훈" scheme="http://kaistizen.net/EE/index.php/weblog/C11/" label="재훈" />

		<category term="독서" scheme="http://kaistizen.net/EE/index.php/weblog/C10/" label="독서" />
 
		<category term="애자일" scheme="http://kaistizen.net/EE/index.php/weblog/" label="애자일" />
 
		<category term="책" scheme="http://kaistizen.net/EE/index.php/weblog/" label="책" />
 
		<category term="프로젝트+관리" scheme="http://kaistizen.net/EE/index.php/weblog/" label="프로젝트+관리" />

		<content type="xhtml">
			<div xmlns="http://www.w3.org/1999/xhtml">

								

					<p><img title="" class="attachment" src="http://farm4.static.flickr.com/3029/3060554245_88d461da49.jpg" alt="" style="margin: 0pt 0pt 0pt 1em; float: right;" />번역을 하다 보니 아무래도 책의 가치를 다양한 각도에서 보게 된다. 독자로선 책의 가격과 그 내용이 제일 중요하다. 남들은 관심조차 가지지 않는 책이라도 독특한 취향을 가진 사람에겐 명작이 되는 법이다. 하지만 번역가 또는 저자의 입장은 다르다. 설사 인세가 아닌 장당 원고료를 받는 입장이라도 내가 번역한 책이 서점가 구석진 자리에서 먼지를 뒤집어 쓰고 있다면 기분 좋을리 없다. 결국 대중성을 생각 각하게 되는데 정말 훌륭한 책이지만 대중성은 부족하다 싶은 책을 만나면 기분이 묘하다. 비록 다른이가 번역한 작품이라도 "이 책으로 손익분기점은 넘겼을라나?"하는 걱정을 한다.</p>

<p><a href="http://farm4.static.flickr.com/3029/3060554245_88d461da49.jpg" class="external" title="http://farm4.static.flickr.com/3029/3060554245_88d461da49.jpg">불확실성과 화해하는 프로젝트 추정과 계획</a>도 그런 책이다. 들은 바에 의하면, 실제로 이 책이 생각만큼 잘 팔리진 않아서 걱정이라 한다. 책이 나오자 마자 사서 훑어보기 시작한 터라 진즉에 이렇게 되지 않을까 생각하긴 했지만, 예상이 맞았다 해도 기분이 좋진 않다.</p>

<p>이제 이 책의 판매가 예상보다 부진한 이유를 알아보자. 서점가를 보면 보통 입문자용 책이 잘 팔린다. 이 책처럼 프로젝트 관리를 다룬 경우라면 보통 250쪽 내지 350쪽에 프로젝트와 시작과 끝을 모두 살펴보는 형식이어야 한다. 책이 두꺼워선 부담스럽고, 새로운 지식과 경험을 배우는 사람이니 특정 지식이나 기술을 상세히 다뤄도 골 아프다. 안타깝게도 <strong>불확실성과 화해하는 프로젝트 추정과 계획</strong>이 바로 이런 범주에 든다. 부록 등을 제외하고 450쪽인데다 프로젝트 과정 중에서도 추정과 계획만 다루기 때문이다. 그러니 독자의 대다수를 차지하는 초심자가 사서 읽기엔 솔직히 힘들 수밖에 없다.</p>

<p>그러나 책 자체는 아주 훌륭하다. 애자일하면 아주 치밀한 계획과는 거리가 먼 듯 보이지만 실제론 그렇지 않다. 자주 피드백을 받아 계획을 수정해야 하기 때문에 되려 만만치 않은 접근법이다. 450쪽아니 되는 분량에 추정과 계획에 관한 내용만 쏟아 부었으니 당연한 일인가?&nbsp;</p>

<p>구체적으로 목차를 들여다 보면, 스토리 점수를 이용한 규모 추정, 재무 지표 등을 활용한 재정적 우선순위 정하기, 카노 모델을 이용한 고객 만족도 조사 같이 매우 구체적이고 실무적인 지식을 전달하려 애쓴 흔적이 보인다. 또한 구체적인 통계와 논문을 먼저 제시하고 자신의 의견을 내세움으로써 반론하기 만만찮은 논리를 만들어낸다. 프로젝트 관리에 대한 책을 20권 이상 읽었는데 그렇지 않았다면 저자의 의견에 한줌의 의심조차 갖기 힘들었을 것이다. 세세히 파고 들면 의견을 달리 하는 부분이 있지만 전체적으론 올바른 접근법이라 생각한다.</p>

<p>책 중간중간에 간단한 제안이나 부연 설명이 달렸는데 개인적으론 <strong>프로젝트에 좀더 많은 시간을 할애하기</strong>(262쪽)가 인상 깊었으니 이 글만 발췌 소개하고 그만 줄일까 한다.</p>

<blockquote>
<p>시릴로는 팀으로 하여금 고도로 집중된 상태를 유지하면서 삼십 분 단위로 작업할 것을 독려하였다(Cirillo, 2005). 그 삼십 분은 두 부분으로 구성되어, 25분 동안은 철저히 일에만 몰두하고 그 뒤 오 분 동안은 쉬도록 짜여 있다. 그는 그 삼십 분을 '<strong>포모도리</strong>(pomodori)'라 불렀는데, 이는 토마토를 일컫는 이탈리아 말로 25분간의 집중적 업무시간이 끝날 때마다 울리도록 맞춰 놓았던 타이머 시계가 토마토 모양이었던 데서 유래한 것이다.</p>
</blockquote>

<p style="text-align:right">이 글은 <a href="http://kaistizen.springnote.com/pages/2166346">스프링노트</a>에서 작성되었습니다.</p>
												
				<br/>
				
<p><a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/80x15.png" /></a><br/>
이 저작물은 <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/">크리에이티브 커먼즈 코리아 저작자표시-동일조건변경허락 2.0 대한민국 라이센스</a>에 따라 이용하실 수 있습니다.</p>

			</div>
		</content>
	</entry>

	<entry>
		<title>똘똘이&#45;스머프의 미투데이 &#45; 2008년 11월 25일</title>
				<link rel="alternate" type="text/html" href="http://kaistizen.net/EE/index.php/weblog/comments/2008_11_25/" />
				
		<id>tag:kaistizen.net,2008:EE/index.php/weblog/index/6.1435</id>
		<published>2008-11-25T19:42:00Z</published>
		<updated>2008-11-26T13:45:06Z</updated>
		<author>
			<name>최재훈</name>
			<email>kaistizen@gmail.com</email>
			<uri>http://kaistizen.net</uri>		</author>


		<content type="xhtml">
			<div xmlns="http://www.w3.org/1999/xhtml">

								

					<div class="me2day_daily_digest">
    <ul> 
      <li>
        집 컴퓨터 한대가 자꾸 죽는다. 전압이나 오버클락킹 문제라는 메시지가 뜨는데, 아무래도 파워나 메인보드가 맛간 듯 하다. 결국 메인보드와 파워를 주문했다. 예상치 않은 출혈.
        <span class="me2_tags">(컴퓨터)</span>
        <span class="datetime"><a href="http://me2day.net/kaistizen/2008/11/11#11:46:18" rel="bookmark" title="퍼머링크" class="datetime">2008-11-11 11:46:18</a></span>
        
      </li>
      <li>
        메인보드, 파워, 사운드 카드, SDHC 메모리 이렇게 네 개를 샀는데 메인보드와 파워 둘 다 불량이었다. 부품 하나가 불량인 적은 있어도 이런 경우는 처음이네.
        <span class="me2_tags">(황당 컴퓨터 수리)</span>
        <span class="datetime"><a href="http://me2day.net/kaistizen/2008/11/13#09:55:36" rel="bookmark" title="퍼머링크" class="datetime">2008-11-13 09:55:36</a></span>
        
      </li>
      <li>
        몸살과 컴퓨터 고장도 수습했으니 이젠 원래 생활로 돌아가자. 일이 많이 밀렸네. 귀찮게 말이지.
        <span class="datetime"><a href="http://me2day.net/kaistizen/2008/11/19#14:29:39" rel="bookmark" title="퍼머링크" class="datetime">2008-11-19 14:29:39</a></span>
        
      </li>
      <li>
        인터넷으로 카드 발급 신청하는데 “보험사에 정보 제공” 항목은 취소가능한데 잘 모르게 꼭꼭 숨겨놨다. 이런 사소한 것 때문에 개인정보가 빠져나가는 듯.
        <span class="me2_tags">(은행 카드 개인정보 사생활)</span>
        <span class="datetime"><a href="http://me2day.net/kaistizen/2008/11/25#23:52:51" rel="bookmark" title="퍼머링크" class="datetime">2008-11-25 23:52:51</a></span>
        
      </li>
      <li>
        비스타 x64 쓴지 일주일이 지났다. 짜증나는 “사용자 계정 컨트롤”만 끄면 정말 편리하다. 잘 안 쓰긴 해도 익스플로러가 상당히 빠르고, Super Fetch가 성능을 잘 끌어내는 듯 하다. 사용자 폴더 구조가 많이 변했는데 익숙해지니 편하고 이래저래 좋다.
        <span class="me2_tags">(윈도우)</span>
        <span class="datetime"><a href="http://me2day.net/kaistizen/2008/11/25#23:56:41" rel="bookmark" title="퍼머링크" class="datetime">2008-11-25 23:56:41</a></span>
        
      </li>
    </ul>
    <p style="background:url('http://me2day.net/images/me2day_icon.gif') no-repeat right top;padding-right:25px;text-align:right; font-size: 0.9em;">
      이 글은 <a href="http://me2day.net/kaistizen" >똘똘이-스머프</a>님의 
      <a href="http://me2day.net/kaistizen/2008/11/11#11:46:18">2008년 11월 11일</a>에서 
      <a href="http://me2day.net/kaistizen/2008/11/25#23:56:41">2008년 11월 25일</a>까지의 
      미투데이 내용입니다.
    </p>
  </div>



												
				<br/>
				
<p><a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/80x15.png" /></a><br/>
이 저작물은 <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/">크리에이티브 커먼즈 코리아 저작자표시-동일조건변경허락 2.0 대한민국 라이센스</a>에 따라 이용하실 수 있습니다.</p>

			</div>
		</content>
	</entry>

	<entry>
		<title>관리되는 래퍼 클래스를 friend로 선언하기</title>
				<link rel="alternate" type="text/html" href="http://kaistizen.net/EE/index.php/weblog/comments/friend_ref_class/" />
				
		<id>tag:kaistizen.net,2008:EE/index.php/weblog/index/1.1434</id>
		<published>2008-11-11T04:01:01Z</published>
		<updated>2008-11-13T01:03:06Z</updated>
		<author>
			<name>최재훈</name>
			<email>kaistizen@gmail.com</email>
			<uri>http://kaistizen.net</uri>		</author>

		<category term="소프트웨어 개발" scheme="http://kaistizen.net/EE/index.php/weblog/C17/" label="소프트웨어 개발" />

		<category term="프로그래밍 언어" scheme="http://kaistizen.net/EE/index.php/weblog/C3/" label="프로그래밍 언어" />
 
		<category term="C++/CLI" scheme="http://kaistizen.net/EE/index.php/weblog/" label="C++/CLI" />

		<content type="xhtml">
			<div xmlns="http://www.w3.org/1999/xhtml">

								

					<pre name="code" class="c++">
// native.h
class NativeClass
{
#ifdef __cplusplus_cli
	friend ref class ManagedClass;
#endif

private:
	int PrivateMethod();
};

// managed.h
ref class ManagedClass
{
private:
	int PrivateMethod()
	{
		return m_NativeObj-&gt;PrivateMethod();
	}

	NativeClass* m_NativeObj;
}
</pre> 

<p>핵심은 <code>__cplusplus_cli</code> 키워드다. 이 키워드가 없어도 되지 않냐? 이렇게 생각하기 쉬운데 그렇지 않다. 네이티브 컴파일러는 <code>ref</code> 키워드를 모른다. 그래서 네이티브 컴파일러가 이 헤더 파일을 참조할 때 반드시 <code>__cplusplus_cli</code> 키워드가 있어야 한다. 그렇지 않으면 컴파일 오류가 난다. </p>

												
				<br/>
				
<p><a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/80x15.png" /></a><br/>
이 저작물은 <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/">크리에이티브 커먼즈 코리아 저작자표시-동일조건변경허락 2.0 대한민국 라이센스</a>에 따라 이용하실 수 있습니다.</p>

			</div>
		</content>
	</entry>

	<entry>
		<title>스크럼 &#45; Agile Software Development with Scrum</title>
				<link rel="alternate" type="text/html" href="http://kaistizen.net/EE/index.php/weblog/comments/agile_software_development_with_scrum/" />
				
		<id>tag:kaistizen.net,2008:EE/index.php/weblog/index/1.1433</id>
		<published>2008-11-11T00:28:00Z</published>
		<updated>2008-11-11T04:06:51Z</updated>
		<author>
			<name>최재훈</name>
			<email>kaistizen@gmail.com</email>
			<uri>http://kaistizen.net</uri>		</author>

		<category term="재훈" scheme="http://kaistizen.net/EE/index.php/weblog/C11/" label="재훈" />

		<category term="독서" scheme="http://kaistizen.net/EE/index.php/weblog/C10/" label="독서" />

		<category term="소프트웨어 개발" scheme="http://kaistizen.net/EE/index.php/weblog/C17/" label="소프트웨어 개발" />

		<category term="방법론" scheme="http://kaistizen.net/EE/index.php/weblog/C9/" label="방법론" />
 
		<category term="스크럼" scheme="http://kaistizen.net/EE/index.php/weblog/" label="스크럼" />
 
		<category term="애자일" scheme="http://kaistizen.net/EE/index.php/weblog/" label="애자일" />

		<content type="xhtml">
			<div xmlns="http://www.w3.org/1999/xhtml">

								

					<p>스크럼이다 린 소프트웨어 개발이다 말이 많은데, <strong>Agile Software Development with Scrum</strong> 역시 이런 관심을 등 엎고 나온 책이다. 책의 목차를 보면 큰 줄기가 눈에 들어오는데, 스크럼을 처음 배우려는 사람에게 무난하다. 무엇을 준비하고 무엇을 실천해야 하는지, 그 이론적 또는 경험적 배경은 무엇인지, 실제로 적용한 사례는 어떤 게 있는지 하나씩 알려준다.</p>

<ol>
	<li><p>스크럼을 시작하며</p></li>
	<li><p>스크럼 준비</p></li>
	<li><p>스크럼의 실천법</p></li>
	<li><p>스크럼 적용하기</p></li>
	<li><p>왜 스크럼인가?</p></li>
	<li><p>왜 스크럼은 통할까?</p></li>
	<li><p>스크럼 적용 고급편</p></li>
	<li><p>스크럼과 조직</p></li>
	<li><p>스크럼의 가치</p></li>
</ol> 

<p>책이나 프로젝트를 통해 다양한 개발방법론을 접한 사람에겐 다소 가벼운 이야기가 될테고, 그렇지 않은 사람에겐 좋은 길잡이가 될 것이다. 사실, 번역서 중에 스크럼을 쉽게 설명한 책이 거의 없으니 나름 의의가 큰 크다. 하지만 내겐 너무나 익숙한 이야기였고, 딱히 새로운 지식을 얻진 못했다. 다만, 오랜만에 내가 하는 일을 돌아보고 새삼 느끼는 점이 많았다. 그러니 개발방법론을 잘 모르는 독자에겐 미안하지만, 책의 소개보다는 내가 느낀 점을 위주로 독후감을 쓸 생각이다.</p>


<br/> 

<h3>1장</h3>

<blockquote cite="">
	<p>인디비쥬얼 사의 스크럼에서 가장 인상 깊었던 점은 스크럼을 시작하면서부터 한 주에 여덟 시간이나 하던 고위 임원들의 회의를 없애버렸다는 사실이다.</p>
</blockquote> 

<p>스크럼만의 이야기는 아니다. 흔히 익스트림 프로그래밍 같은 애자일 방법론을 생각할 때 귀찮은 문서화나 회의를 없애고 개발자를 위한 환경을 구축한다고 생각한다. 그러나 내가 생각하기엔 피드백이야 말로 소프트웨어 개발의 승패를 쥔다. 애자일 방법론이란 결국 피드백을 빨리 주고 받는 환경을 만드는 것이다. 그래서 애자일을 하면 회의가 없어지는 게 아니고 되려 많아진다(문서화는 줄어든다고 봐야 한다). <strong>일일 스크럼 회의</strong>가 좋은 예이다. 15분 가량 매일 같이 회의를 한다. 회의 주기를 줄여서 의사소통의 공백을 줄인다. 사람들은 회의하길 꺼려한다. 한번 할 때마다 별 이야기도 아닌데 30분, 1시간, 또는 몇 시간을 붙잡히기 때문이다. 그러나 이는 회의 자체의 문제라 보기 힘들다. 회의가 길어지는 이유야 많지만, 무엇보다도 한꺼번에 많은 이야기를 하기 때문에 그런 탓이 크다. 할 이야기가 많다 보니 한번에 한 주제에 집중하지 못하고 이 이야기했다 저 이야기했다 한다. 그러니 되려 자주 함으로써 회의의 필요성을 줄이겠다는 역발상이 힘을 발휘한다.</p>

<p>스크럼에선 <strong>제품 백로그</strong>와 <strong>일일 스크럼 회의</strong>을 특히 중요시한다. 용어가 어려워서 그렇지 사실 둘다 경량화된 방법론에선 하나 같이 강조하는 부분이다. 일일 스크럼은 앞서 다뤘고, 제품 백로그는 우선순위를 정해 일하자는 이야기일 뿐이다. 이게 참 기본이면서 하나 같이 제대로 못하는 부분이다. 능력있는 관리자 밑에서 일을 배웠거나 스스로 일하는 법을 익힌 일부 사람만 이렇게 일한다. 그러나 문제는 개인의 능력이 좋고 나쁘냐란 게 아니고, 이러한 프로세스를 신입사원조차 당연하게 받아들이는 환경과 체계를 구축하는 것이다. 스크럼과 같은 애자일 방법론에선 이런 체계를 잦은 피드백과 검토를 통해 내재화할 수 있다고 주장한다. 이렇게 자연스럽게 도입된다면 좋은 일이다.</p>

<p>우선순위와 일일 회의는 어렵지 않은 개념이라 실천하기 쉽지만, 알다시피 이론적으로 쉽다는 이야기고 막상 조직에 도입하려면 문제가 많다. 자신이 막강한 권한을 가진 관리자면 모를까 팀 구성원 중 한명일 뿐일 때, 익숙치 않은 무언가를 해보자고 설득하고 끈기있게 실천해나가기란 쉽지 않다. 도입 과정에서 문제가 생기면 다음번엔 더 보수적으로 반응하기 때문에 미래를 위해서라도 신중해야 한다. 단순히 <q>내일부턴 일일 회의를 합시다!</q>라고 의욕찬 발언을 한다고 될 문제가 아니다. 결국, 더 나은 방법이 있다는 사실을 공부해서 아는 게 시작이고, 이를 현명하게 실천해나가는 게 그 다음이다. 그러고 나서 비로소 <q>어떻게 하면 더 잘 할까?</q>를 고민해야 한다. </p>

<p>소프트웨어 프로젝트에 대해 책을 십여권 넘게 읽었지만 여태 <em>일일 회의</em>조차 도입 못했던 게 사실이다. 이제사 이런 제도를 정착시키려 하는 중이고 성공 여부는 한참 지나봐야 알겠다. </p>

<br/>


<h3>팀 소유권</h3>

<p>익스트림 프로그래밍엔 코드 공동소유권(Collective Code Ownership)이란 개념이 있다. 간단히 말해 <em>이건 내가 짠 코드니까 넌 건드리지마!</em>란 태도를 배척하자는 이야기다. 부분 최적화가 아닌 <strong>전체 최적화</strong>를 강조하는 사례인데, 결국 프로젝트와 팀의 성공을 위해 어떠한 제한도 두지 않고 열린 마음으로 협력하겠단 선언이다. 스크럼 역시 이러한 태도가 필수적이다.</p>

<blockquote cite="">
	<p>팀의 모든 사람은 스프린트 목표 달성에 필요한 것이라면 무엇이든지 가리지 않고 하고</p>
</blockquote> 

<p>일전에 <a href="http://english.kaistizen.net/entry/Team-Ownership">영문 블로그에 밝힌 적이 있지만</a>, 경력이 1년, 2년, 해를 거듭해갈수록 소프트웨어 개발 현장의 좋은 점과 나쁜 점을 많이 알게 된다. 개인의 관점에서 보면 소스 코드를 자신의 소유물로 여기는 사람이 생각보다 많다는 사실이 나쁜 점 중 하나다. 무척 놀라운 일이지만 정말 그렇다. 이런 현상의 배경엔 사람을 쉽게 대체가능한 기계 부품 정도로 여기는 경영진들의 횡포가 있지만, 환경이 바뀌거나 개선된 다음에도(그러니까 이직한 이후에도) 자신의 방어 기제를 버리지 못하는 게 문제다. 다행히 나는 이런 사람과 함께 일하지 않지만, 만약 그런 사람이 포함된 팀이라면 어떻게 일해야 할까 무척 고민된다. </p>

<p>경험해보니 팀 단위 인센티브를 도입하더라도 내가 아닌 팀 중심적 사고를 이끌어내기가 쉽지 않다. 솔직히 팀 단위 인센티브란 것도 대체로 보면 그 안에서 공을 평가하기 때문에 문제다. 보통 일한 만큼 받는 게 당연하다고 생각하기 쉽지만, 그리고 나도 그렇게 생각했지만, 전체 최적화를 방해하는 요소가 되기 마련이라 비판하는 사람이 생각보다 많다. 팀 내에선 인센티브 폭을 작아야 <q>난 내 할 일만 잘하면 돼</q>라는 태도가 없어진다.</p> 

<p>어쨌건 간에 저 단순한 한마디, <q>팀의 모든 사람은 스프린트 목표 달성에 필요한 것이라면 무엇이든지 가리지 않고 한다</q>가 말처럼 쉽진 않다.</p>



<br/>

<h3>거창한 방법론</h3>

<blockquote cite="">
	<p>나는 방법론이 하라는 대로 다 했어. 분명 개발자가 방법론이 지시한 내용을 제대로 하지 않았을 거야.</p>
</blockquote> 

<p>이런 말하는 컨설턴트나 프로젝트 관리자가 많고 고충을 이해하지만, 이런 생각도 해봐야 하지 않을까? <q>방법론 자체가 글러먹은 건 아닐까?</q> 애당초 모든 사람이 방법론의 세부사항을 하나하나 숙지하고 따라하리란 가정 자체가 웃기다고 생각한다. 그럴 능력이 되는 사람들이 왜 자신들만의 방법론을 안 만들고 여러분이 제안하는 방법론을 따를지 한번쯤 생각해봐야 한다. 무턱대고 <q>이게 옳은 방법이니까 무조건 따라야 해</q>라고 했다가 결과가 신통찮으면 저자가 말한 것처럼 상황은 악화되기 때문이다.</p>

<blockquote cite="">
	<p>죄책감에 이어 무관심이 생기기 시작한다. 최선을 다했음에도 불구하고 계속해서 기대를 만족시키지 못한 작업자들은 결국 최선을 다하지 않게 된다. </p>
</blockquote> 

<br/>


<h3>마치는 글</h3>

<p>비슷한 내용이라도 내 업무, 그러니까 소프트웨어 개발과 관련된 책이라면 가리지 않고 여러 번 읽는다. <q>뭐야, 다 아는 이야기잖아!</q>, <q>별 것 없네!</q>라고 말할 정도가 되려면 그만한 경험과 지식을 체득해야 한다. 단순히 <em>안다</em>는 정도론 부족하다. <strong>스크럼</strong>에서 딱히 새로운 지식을 얻진 못했지만, 지식과 경험을 서로 대조해보고 배우고 느낀 점이 많다. 그러나 한번에 너무 많은 이야기를 하자니 긴장감이 떨어져서 다음번에 <strong>불확실성과 화해하는 프로젝트 추정과 계획</strong>을 소개할 때 나머지도 풀어볼 생각이다.</p>


												
				<br/>
				
<p><a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-nc-sa/2.0/kr/80x15.png" /></a><br/>
이 저작물은 <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/kr/">크리에이티브 커먼즈 코리아 저작자표시-동일조건변경허락 2.0 대한민국 라이센스</a>에 따라 이용하실 수 있습니다.</p>

			</div>
		</content>
	</entry>

	<entry>
		<title>똘똘이&#45;스머프의 미투데이 &#45; 2008년 11월 10일</title>
				<link rel="alternate" type="text/html" href="http://kaistizen.net/EE/index.php/weblog/comments/2008_11_10/" />
				
		<id>tag:kaistizen.net,2008:EE/index.php/weblog/index/6.1432</id>
		<published>2008-11-10T19:39:00Z</published>
		<updated>2008-11-11T00:02:59Z</updated>
		<author>
			<name>최재훈</name>
			<email>kaistizen@gmail.com</email>
			<uri>http://kaistizen.net</uri>		</author>


		<content type="xhtml">
			<div xmlns="http://www.w3.org/1999/xhtml">

								

					<div class="me2day_daily_digest">
    <ul> 
      <li>
        콜드 케이스 보다가 문득 왜 게임의 배경은 항