'버전관리'에 해당되는 글 4건

  1. 2012.07.25 상용 툴 이야기 - 버전/이슈관리 툴 (4)
  2. 2011.07.18 Mercurial Tutorial - (1) Subversion 재교육 (3)
  3. 2008.03.16 Features of SCM tool
  4. 2007.10.12 브랜칭의 미학 (2)

상용 툴 이야기 - 버전/이슈관리 툴

|

요즘은 IDE들이 잘 나오면서 의미가 약간 퇴색되긴 했지만 기본적으로 프로그래밍에 필요한 3대 툴을 꼽으라면 에디터-컴파일러-디버거를 얘기할 수 있다. 사실 컴파일러만 있으면 나머지 두 가지는 이 대신 잇몸으로라도 해결이 가능하긴 하지만...

개인적인 생각으로는 컴파일러가 없는 건 당연히 말이 안 되고, 나머지 두 가지는 생산성 향상을 위해서는 꼭 필요하다는 것이 좀 더 정확한 표현일 듯 하다.


그리고 위 세 가지 이외에 최근 필수적인 툴로 떠오른 것이 바로 버전관리 툴이다. 최근이라고 하기엔 이미 많이 지나긴 했지만... SCM(Source Configuration Management) 툴이라고도 하지만 여기서는 그냥 이해하기 쉽게 버전관리 툴이라고 하겠다.


내가 가장 먼저 접한 버전관리 툴은 그야말로 '원조' 타이틀이 어색하지 않은 CVS(Concurrent Version System)였다.

원래 유닉스에는 RCS(Revision Control System)라는 툴이 존재했는데 파일의 변경 내역을 관리해 주는 툴이다. 헷갈리면 안 된다. 저 툴은 파일 하나만 관리할 수 있다 -_-;

소스 변경 내역 관리 자체가 안 되던 시점에는 RCS만 해도 쓸만하지 않았을까 싶다. 하지만 소스란게 파일 하나만 있는 것도 아니고... 그래서 RCS를 기반으로 여러 파일을 같이 관리할 수 있는 툴이 제작되었고 그것이 CVS다.


대학교 때 어떻게 알고선 혼자서 처음 CVS를 써보고서 '오~' 이랬던 기억이 아직도 생생하다. 교수들도 협업에 대한 노하우는 가르치지 않았으니깐...


그리고 입사한 첫 회사... 버전관리 툴이란게 존재하지 않았다 -_-;;

FTP에 개인이 작업한 소스를 압축해서 "개나소_20001010.zip" 이런 식으로 파일명을 붙여서 며칠에 한 번씩 올려놓는 식으로 작업하고 있는 것이었다. 오마이갓... 물론 작은 회사였다.

결국 선임 개발자들에게 CVS란 걸 가르쳐 주고 설득시켜서 적용시킬 수 밖에 없었다. 당연히 그 분들도 '오~'하고 감탄... 지금 생각해도 나보다 선임인 개발자가 서너명 있었는데 아무도 몰랐다는게 더 신기하다 -_-;

여튼 작은 회사였으니 상용 툴을 쓰는 건 뭐 거의 기대할 수 없었고... 개발도 gcc랑 vi로만 했고... 물론 ctags와 csope까지 포함... 아 이것도 내가 전파했군 -_-;


두번째 입사한 회사에서는 Source Offsite를 쓰고 있었다. 지금도 그런지는 모르겠지만 당시에는 솔직히 왜 돈 주고 사서 쓰는지 이해가 안 되는 툴이었다. 그 회사는 그래도 비교적 잘 나가던 회사였고 툴에도 그럭저럭 투자를 하는 편이었는데... 소스 오프사이트는 정말 아니었다.

예전 VS의 비주얼 소스세이프의 원격판인 셈이었는데 문제는 방식이 Lock-Check in-Unlock이었다. 변경할 파일에 Lock을 걸고 수정을 하고 Unlock을 해야 하는 방식인데 지금은 이런 방식의 툴이 거의 없지만 구현하기는 간단하다는 장점은 있을라나... 뭐 그것도 제작사 입장이고...-_-;


결정적인 문제는 File에 Lock을 걸면 다른 사람들은 아무도 Lock을 걸 수 없었다. Lock을 걸지 않으면 파일이 read-only라 수정이 불가능했다.

한 명이 이리저리 고쳐보면서 고민하는 시간이 길어지는 경우가 생기면 다른 사람들은 손가락 빨고 있어야 되는 구조였다.

강제로 read-only를 풀 수야 있지만 버전관리 툴에서 관리를 해 주지 않으므로 별로 의미가 없다. 그냥 자기가 고친 파일들 기억해 놓고 있다가 Lock이 풀리면 체크인하거나 해야 했다.

그래서 저 당시 내가 썼던 방법은 노트북에 SVN을 깔아 소스오프사이트 Working Copy를 복제해서 따로 작업하는 것이었다 -_-;


그리고 다른 문제를 말하자면, 해외 출장 개발이 많았던 회사이고 네트웍이 열악한 지역으로 출장을 가다 보니 해외에서는 하도 느려서 소스 서버에 붙어서 작업한다는게 거의 불가능했다. 같이 출장나가던 팀원들을 설득해서 내 노트북의 SVN에 붙어서 작업하도록 한 적도 있었는데... 초반엔 쓸만했지만 일이 있어서 내가 일찍 귀국하자 결국 흐지부지 되어버렸다. 그 때 지금의 git나 mercurial이 있었으면 굉장히 유용하지 않았을까 싶다.


소스 오프사이트에 학을 뗐던 에피소드 중 결정적인 것은 팀에서 두바이 출장을 가 있었고 나는 국내에 있었을 때였다. 내가 Lock을 걸고 일하다가 깜박하고 그대로 퇴근을 했는데 한두시간 후 두바이에서 국제전화가 걸려왔다. 파일에 Lock 걸려 있다고 -_-;;;

집의 컴퓨터에서는 회사일이 불가능했기 때문에 결국 내 소스 서버 계정을 알려줘서 두바이에서 직접 Lock을 풀도록 할 수 밖에 없었다 ;;


그리고 지금 회사는... Perforce를 쓰고 있다.

가격도 꽤 비싼 버전관리 툴인데... 1명당 라이센스가 대략 $600?

성능이나 기능은 만족하고 있다. 대규모 프로젝트에도 무리가 없고... 소스 오프사이트처럼 락을 걸어야 하는 방식이 살짝 마음에 안들긴 하지만 락을 걸어도 다른 사람이 수정 가능하기 때문에 별 문제는 없다.


지금은 이슈관리 툴 또한 꽤 좋은 상용 툴인 Jira를 쓰고 있다(이전 회사들은 죄다 Trac이나 BugZilla 같은 오픈 소스 아니면 엑셀 -_- 이었다).

버전 관리에 비해 이슈 관리는 약간 중요성이 떨어져 보이기도 하는데 사실 간단하게는 엑셀로도 할 수 있는 일이 맞긴 하다. 실제로도 그렇게 하는 경우도 많고...

하지만 이슈 관리는 Issue Tracking이라고도 불리는 만큼 문제의 '추적'이 중요하고, 예전에 발생했던 문제인지를 확인하는 등의 기능과 다중사용자를 위한 UI에서는 아무래도 엑셀보다 전문 툴을 사용하는 것이더 바람직하다고 할 것이다.


버전 관리나 이슈 관리는 사실 오픈 소스 툴도 잘 되어 있긴 하지만... 생산성 제고를 위해서 적합하고 좋은 툴을 선택하는 것도 회사가 신경써야 할 일이 아닐까 싶다.

Trackback 0 And Comment 4

Mercurial Tutorial - (1) Subversion 재교육

|

이 글은 저자인 조엘 스폴스키의 허락을 득해 hginit.com의 내용을 번역한 것입니다. Mercurial을 사용하시는 분들께 도움이 될까 해서 올립니다.



우리 회사의 프로그래머들이 Subversion에서 Mercurial로 전환하기로 결정했을 때, 소년이여 나는 혼란스러웠다네(조엘 스폴스키는 FogCreek이라는 회사의 CEO이기도 합니다 - 역주).

일단, 나는 왜 우리가 바꾸면 안 되는지에 대한 모든 종류의 허접한 이유를 찾았다. "우리는 중앙 서버에 저장소를 보관해야 해. 그게 더 안전하잖아." 라고 말했지만, 그거 아세요? 내가 틀렸어요. Mercurial에서는 모든 개발자가 전체 저장소의 복사본을 각자의 하드 드라이브에 갖고 있다. 실제로 그게 더욱 안전하다. 그리고 어쨌든 거의 모든 Mercurial을 사용하는 팀은 당신이 마지못해 백업을 하고 실론(배틀스타 갤럭티카의 기계 종족), 스타워즈 제국군, 래브라두들(래브라도와 푸들의 혼혈견)의 3단계 보안 체계에 보호되도록 중앙 저장소도 따로 운영한다 - 혹은 그 외 당신의 IT부서에서 요구하는 뭐든지(조크가 안드로메다네요 - 역주 -_-).

"분산 버전관리의 문제는 브랜치를 만들기가 너무 쉽다는 거야."라고 나는 말했다. "그리고 브랜치는 항상 말썽을 일으켜" 이것도 잘못된 사실이다. 나는 일종의 편견에 사로잡혀 있었다. Subversion에서 브랜칭하는 것은 Subversion이 머지에 필요한 정보를 충분히 갖고 있지 않기 때문에 문제가 된다. 하지만 Mercurial에서는, 머지가 어렵지 않고 간편하다. 그러므로 브랜칭도 특별한 작업이 아니며 안전하다.

그리고서 나는 말했다. "좋아, 써보자구. 하지만 내가 잘 쓰리라고는 기대하지마" 그리고 제이콥에게 Subversion에서 일반적으로 하던 작업들에 대해 Mercurial에서 하는 방법과 비교한 치트 시트를 만들어 달라고 했다.

지금 그 치트 시트를 보여줄 수도 있지만 그러진 않을 것이다. 그 접근 방식이 몇 달 동안 내 머리를 뒤죽박죽으로 만들어 놓았다 -_-

당신이 Subversion을 계속 써왔다면, 음, 이걸 어떻게 예의 바르게 설명해야 하나? 당신의 뇌는 어쨌든 피폐해져 있다. 아니, 이건 좀 아닌 표현인 듯. 당신은 약간의 '재교육'이 필요하다. 나는 6개월간 뒤죽박죽이 된 머리를 싸매며 Mercurial이 Subversion보다 약간 더 복잡하다고 생각했었지만, 사실은 내가 동작 방식을 제대로 이해하지 못했기 때문이었다. 한 번 내가 그걸 깨닫고 나자 - 뾰로롱! - 그건 정말 단순했다.

그래서 나는 이 튜토리얼을 당신들을 위해 쓰면서 Subversion의 용어로 설명하지 않기 위해 매우 신경썼다. 그러면 머리만 더 아프니까. 이 첫번째 장은 깨끗한 상테에서 Mercurial을 배우기 위해 가능한 그 동안의 데미지를 없애기 위한 시작이다.

만약 Subversion을 써 본 적이 없다면 이번 장은 넘어가도 좋다.

준비 되었나요? 그럼 짧은 퀴즈로 먼저 시작하자. 

Q1. 당신은 한 번 만에 완벽한 코드를 짤 수 있나요?

여기에 '네'라고 대답했다면 당신은 거짓말쟁이거나 사기꾼이다. 다시 해보시길.

새로운 코드란 건 버그를 내재하고 있다. 새로운 코드가 안정적으로 동작하기 위해서는 시간이 더 필요하다. 그리고 그 시간동안, 팀의 다른 개발자들은 트라우마에 시달릴 것이다(니 버그 때문에 다른 사람들이 죽어난다는 거 - 역주).

Subversion의 동작 방식은 이렇다.

  • 당신이 새로운 코드를 체크인(흔히 말하는 커밋)하면, 다른 모든 사람들이 그걸 받아본다.

근데, 당신이 작성한 모든 새로운 코드는 버그를 갖고 있을 수 있으므로, 당신은 선택을 할 수 있다.

  • 당신은 버그가 내재된 코드를 체크인 하고 다른 사람들을 미치게 놔둔다.
  • 혹은, 코드가 안정화 될때까지 체크인하지 않고 둔다.

Subversion은 언제나 당신에게 이 잔인한 딜레마를 안긴다. 금방 작성된 새로운 코드로 인해 저장소가 버그 덩어리가 되든지, 새로 쓰여진 코드인데 저장소에 없든지 (흔히 몇몇 회사에서 '개발자별 브랜치'라는 말도 안 되는게 존재하는 이유가 된다 - 역주).

Subversion 유저로서, 우리는 이런 존재가 납득이 안 가는 딜레마에 빠지곤 한다.

Subversion 팀 멤버들은 종종 며칠이나 몇주씩 체크인 없이 보낸다. Subversion 팀에서 신입들은 무슨 코드든 체크인해서 빌드를 깨먹을까봐 두려워하고 그것이 선임 개발자(뭐든간에) 마이크를 열받게 할까봐 걱정한다. 마이크는 빌드가 깨져서 한 번 열 받으면, 인턴의 파티션으로 날아 와 모조리 엎어버리고 외친다, "이제 회사 나오지 마!" (물론 뻥이다, 하지만 불쌍한 인턴들은 실제로 바지를 적실 지도)

체크인에 대한 이런 모든 두려움은 사람들이 몇 주씩이나 버전 관리의 이득을 보지 못하게 만들고 체크인할 때 도움을 얻으려고 다른 선임 개발자를 찾게 된다. 쓰지도 못한다면 버전관리가 왜 필요하지?

여기 Subversion의 저장소 구조에 대한 간단한 그림이 있다.



Mercurial에서는 모든 개발자가 자신의 데스크탑에 있는 자신만의 저장소를 따로 갖고 있다.



그러므로 당신은 당신의 코드를 당신만의 저장소에 커밋할 수 있고 언제든지 버전관리의 유용함을 누릴 수 있다. 언제든, 당신의 코드가 적당히 작성되었다면 커밋하면 된다.

그리고 코드가 안정적이 되었고 새로운 코드를 다른 사람들에게 쓰게 하려고 한다면 그간 변경된 코드를 당신의 저장소에서 중앙 저장소로 밀어주면(push) 된다. 그럼 다른 모든 사람들은 중앙 저장소에서 코드를 당겨(pull) 올 수 있고 당신의 코드를 보게 될 것이다.준비가 되었다면.

Mercurial은 새 코드를 커밋하는 것과 다른 사람에게 전달하는 것이 구분된다.

그리고 그것은 당신이 다른 사람이 당신의 코드를 가져갈 수 없도록 커밋할 수 있다는 것을 의미한다(hg com). 작성한 코드가 쌓이고 안정적이고 잘 돌아갈 때에 당신은 코드를 메인 저장소에 보내주는 것이다(hg push).


커다란 컨셉 차이 한 가지 더

각각의 길 이름이 어떻게 정해지는지 아는가?

좋아요, 별로 대단한 건 아니지만 일본의 경우를 살펴봅시다.
일본에서는 보통 길 사이의 블록에 번호를 붙이고, 매우매우 중요한 길에 대해서만 이름을 붙인다.

여기에 Subversion과 Mercurial과 유사한 차이점이 있다.

Subversion은 리비전(revision) 단위로 생각하는 경향이 있다. 리비전이란 어떤 특정한 순간의 (저장소의) 전체 파일시스템을 보는 것이다.

Mercurial에서는 체인지셋(Changeset) 단위로 생각한다. 체인지셋이란 어떤 리비전부터 그 다음 리비전까지의 변경 내역이다.
(예를 들어 rev 1에 파일 내용이 int a=1; 이었고 rev 2에 int a=2; 였다면, Subversion은 리비전 별로 해당 파일의 내용을 갖고 있지만 Mercurial은 'rev 1에서 rev 2로 가면서 int a=1이 int a=2로 바뀜'이라는 식의 정보를 저장한다 - 역주)

6개랑 반 다스, 무슨 차인데? -_-

여기 차이점이 있다. 당신과 내가 어떤 코드를 갖고 작업하면서 브랜치를 따로 각자의 워크스페이스에서 각자의 코딩을 마구 했다면 서로 코드가 제법 차이가 나게 될 것이다.

우리가 머지를 해야 할 시점이 왔을 때, Subversion은 양쪽의 최신 리비전을 살펴보고 이것들을 어떻게 조각낸 뒤에 합쳐서 하나의 끔찍한 혼란 속으로 몰아넣을 건지 판단한다. 그리고 대개는 머지가 실패하고, 수많은 "머지 충돌(merge conflict)" 메시지를 내뱉지만 실제로는 머지 충돌이라고 할 수 없다. Subversion이 우리가 어떻게 작업했었는지를 파악하지 못하기 때문에 생기는 결과다.

그에 반해 우리가 Mercurial로 작업했다면, Mercurial은 각각의 체인지셋을 저장하느라 바빴을 것이다. 그리고 우리가 머지를 하기 원할 시점에 실제로 Mercurial은 많은 정보를 가지고 있다. Mercurial은 우리가 리비전마다 뭘 바꿨는지 알고 있으며 마지막 리비전만 갖고 어떻게 합칠 지 고민하는게 아니라 체인지셋을 하나하나 재적용하는 방식으로 머지를 수행한다.

예를 들어 내가 함수 하나를 약간 바꾼 뒤에 그 함수를 다른 위치로 옮겨버렸다면 Subversion은 그 과정을 알고 있지 못하고 머지할 때 그냥 새로운 함수가 갑자기 생겼다고 생각할 것이다. 반면 Mercurial은 그것들을 구분해서 함수가 변경되고, 옮겨진 일련의 과정을 기억하므로 당신이 그 함수를 따로 수정했다 하더라도 Mercurial은 우리의 수정 내역을 성공적으로 머지할 것이다.

Mercurial은 모든 것을 체인지셋의 관점에서 생각하므로 당신은 그 체인지셋들로 재미있는 것들을 해볼 수 있다. 예를 들면 당신은 당신의 체인지셋을 중앙 저장소에 올려서 다른 모든 사람들이 받아보게 하는 대신 팀의 다른 친구의 개인 저장소로 테스트 목적으로 그걸 밀어 보내줄 수도 있다.

만약 이것들이 좀 헷갈려도 걱정하진 마시길 - 이 튜토리얼을 보다보면 다 이해될 것이다. 지금 가장 중요한 것은 Mercurial이 "리비전"이 아니라 "체인지셋" 단위로 생각한다는 것이다. 그래서 Subversion보다 훨씬 더 머지 능력이 뛰어나다.

그리고 그로 인해 당신은 브랜치와 머지의 공포에서 해방 될 수 있다.

재밌는 얘기가 듣고 싶나? 내가 얘기 해 본 거의 모든 Subversion 팀들은 나에게 매우 비슷한 내용의 얘기들을 해 주었다. 이 이야기는 꽤 일반적이라 이름을 "Subversion 스토리 #1" 이라고 붙여야만 될 듯. 여튼 스토리는 이렇다. 특정 시점에 늘 그렇듯 고객에게 넘길 출시 버전을 위해 그들은 개발 버전으로부터 코드 브랜치를 시도했다. 그리고 그들은 나에게 똑같이 "머지 전까지는 좋았는데 그 다음은 악몽이었어요"라고 말했다. 5분만에 끝났어야 할 작업이 6명이 결국 2주 동안 그간 수정했던 버그를 하나하나 출시 버전에서 개발 버전에 수동 머지하는 사태가 벌어진 것이다.

그리고 거의 모든 Subversion 팀들은 나에게 "다시는 안 할 거에요"라고 하곤 브랜치를 하지 않겠다고 맹세했다(-_-). 그래서 이제 그들이 해야 할 일이 또 있다. 각각의 새로운 기능을 하나의 커다란 #ifdef 블록으로 묶는 것이다(브랜치 하나에서 작업하려니 새로운 기능이 버그를 일으키면 곤란하므로 필요시 disable시킬 수 있게 #ifdef로 묶는 다는 얘기 - 역주). 그래서 그들은 하나의 브랜치로 작업할 수 있게 되었고 디버깅이 끝날 때까지는 고객이 그 기능을 사용해보지 못하게 할 수 있겠지만, 솔직히 멍청한 짓이다 (어쨌든 출시버전에도 #ifdef로 묶인 불안정한 코드가 들어가는데 실제로 동작은 안 하겠지만 별로 좋은 방식이라곤 할 수 없다 - 역주).

안정화 버전과 개발버전을 따로 가져가는 것은 명백히 버전 관리 도구가 당신이 할 수 있도록 해줘야 될 일이다.

Mercurial을 당신이 사용하게 되더라도 곧바로 깨닫지 못할 수도 있지만, 브랜치가 다시 할만한 일이 된다면 당신은 더 이상 두려워 할 필요가 없다.

당신은 팀 저장소도 따로 가질 수 있으며(회사 전체 저장소가 아닌), 더 작은 팀이 분리되어 새 기능에 대해 따로 협업할 수도 있다. 그리고 작업이 끝나면 메인 개발 저장소에 머지할 것이고 성공적일 것이다.

또한 QA 저장소를 따로 두어서 QA팀에게 테스트를 하게 할 수도 있다. 테스트 해보고, 잘 작동한다면 QA팀이 변경사항을 다시 중앙 저장소에 푸시하면 된다. 중앙 저장소에는 항상 테스트된 코드가 존재하면서 안정적인 상태를 유지할 수 있고, 잘 동작할 것이다.

또 혹은 분리된 저장소에서 당신만의 실험적인 기능을 작업해 볼 수도 있고 잘 동작하면 중앙 저장소에 머지해도 된다. 잘 동작하지 않으면 그냥 버리면된다. 어쨌든 중앙 저장소의 코드는 잘 동작하니까.


마지막 컨셉 차이

Subversion과 Mercurial의 마지막 주요 컨셉 차이는 대단한 것은 아니지만 당신이 몰랐다면 도움될 만한 것이다.

Subversion은 기본적으로 파일들에 대해 리비전을 매기지만, Mercurial은 언제나 전체 소스 코드 트리를 대상으로 리비전을 관리한다.

Subversion에서 하위 디렉토리에서 커밋을 해본 적이 있다면 알 것이다. 커밋은 단지 현재 위치한 하위 디렉토리와 그 밑의 서브 디렉토리들에 존재하는 변경사항만 감지한다. 이것은 다신이 다른 디렉토리에서 작업한 변경 사항을 빠뜨리는 경우가 생길 수도 있다는 것을 의미한다. 반면 Mercurial은 모든 명령이 전체 소스 트리에 대해 적용된다. 당신의 코드가 c:\code에 있고, hg commit을 실행했다면 어디서 실행하든 c:\code와 그 하위 디렉토리들에 대해 동일하게 commit이 적용될 것이다.
(예를 들어 repo\a\a.c를 고치고 repo\b\ 밑에서 커밋을 실행하면 svn은 아무것도 못 찾지만 Mercurial은 다른 디렉토리의 변경된 파일도 커밋을 시도한다. 근데 개인적으로는 꼭 이게 svn의 단점 같지는 않다 - 역주)

이건 대단한 내용은 아니다. 만약 당신이 매우 큰 소스 트리에서 작업하고, 팀 사람들이 각자 맡은 서브 디렉토리에서만 주로 작업한다면 Mercurial을 쓰는 건 별로 좋지 않을 수도 있다 - 프로젝트별로 더 작은 저장소를 여러개 가지는 방식이 더 적합할 것이다.


마지막으로...

내가 당신들에게 단언할 수 있는 건 이거다.

Mercurial이 Subversion보다 더 좋다 (-_-). 

팀으로 소스 작업을 하든, 혼자서 코딩을 하든 Mercurial은 좋은 수단이다.

그냥 더 좋다 (-_-). 

그리고 만약 Mercurial이 동작하는 것을 이해하고 그것이 동작하는 방식대로 일하며, Mercurial을 배우려 하지 않고 예전 Subversion의 방식대로 일하면서 Mercurial과 싸우려 들지 않는다면, 훨씬 행복하고 성공적일 것이다.

초반에는 아마 예측컨대, Mercurial을 포기하고 Subversion으로 돌아가고 싶을 것이다. 뭔가 어색하고, 외국에 이민 온 것 같고, 향수병에 걸려 갖은 합리화를 하려고 들 것이다. 예를 들면, Mercurial은 저장 공간을 너무 많이 잡아먹는다거나 등등, 하지만 실제로는 Subversion보다 공간을 덜 차지한다(정말이다!).

여하튼, 그리고 나서는 브랜치 같은 기능들을 저장소 복제가 아닌(이건 뭐 선택의 문제일 듯도 - 역주) Subversion의 방식으로 계속 해보다가 잘 안되면 당신은 다시 Subversion으로 돌아갈 것이다. Subversion의 방식이 아닌 Mercurial의 방식을 배우도록 해야 된다. 날 믿어라, 잘 될 것이다.

또 혹은 당신은 제이콥이나, 아니 제이콥 같은 일을 하는 당신 팀 사람에게 찾아가 "Subversion -> Mercurial 기능 요약(Cheat Sheet)"을 받아 와서는 3개월 동안 svn up 같은 기능을 하는 것처럼 보이는 hg fetch에 대해 고민하며(fetch는 확장 기능이며 더욱 헷갈릴 수 있으므로 초반엔 쓰지 않기를 권합니다 - 역주) 실제로 fetch가 어떻게 동작하는 지에 대한 고민은 하지 않고 어느 날 Mercurial을 욕할 것이다. Mercurial이 어떻게 동작하는 지에 대해 고민하지 않은 자신에 대한 비난은 없이 말이다.

내가 다 해봐서 당신이 뭘 하게 될 지 안다 -_-;

나와 똑같은 실수는 하지 않길 바란다. Mercurial을 배우고 믿고 어떤게 그것의 방식인지 익히면 버전 관리에 대한 모든 것이 자연스레 넘어가게 될 것이다. 당신네 경쟁사들이 라이브러리 업데이트를 한답시고 몇 주간 머지 오류를 잡느라 바쁠 동안 당신은 그냥 hg merge를 타이핑하고는 "음, 좋은데, 잘 되는군"이라고 말하면 끝이다. 선임 개발자 마이크는 열불내지 않고 인턴이랑 담배 한 대 피러 가서 친해질 수 있을 거고 그러다 보면 봅이 오고... 인생이 행복해질 거다 :)

Trackback 0 And Comment 3

Features of SCM tool

|

제목을 잘 하지도 못하는 영어로 써서 죄송합니다 -_-

SCM은... 쉽게 말하면 버전 관리라고들 하죠. Source Configuration Management의 약자입니다.
CVS, Subversion같은 거요. 아니면 비주얼 소스 세이프라든가... 돈 많은 회사면 Clear Case 쓸 수도 있고...
이런 거 안 쓰세요? 쓰자고 건의하세요, 힘들어 죽어버릴 거 같다고...ㅡㅡ; 못 쓰겠대요? 옮기세요... 그 회사엔 붙어 있어도 좋은 꼴 못 봅니다 -_-;

CVS든 SVN이든 여기저기 많이 쓰긴 하지만, 기본적인 SCM의 기능들이랄까 그 개념은 잘 모르고 쓰는 경우가 많은 것 같습니다.
프로그래밍 언어, 자료구조, 알고리즘 등은 학교에서 가르치지만 막상 이런 실용적인 것들은 가르치지 않지요. GDB나 CVS 처음 써보고 무척 감탄했던 기억이 나는군요. '세상에 이런 것도 있었구나'하는 느낌...? -_-

SCM 툴도 기본적인 원리나 개념들은 관련 S/W들이 오랜동안 개발되고 숙성되어 오면서 충분히 정립된 상태라고 볼 수 있을 것 같습니다. 그런 것들에 대해 쓰는 글입니다.


관리 방식

SCM은 '협업'을 위한 툴이므로 소스 파일을 어떻게 관리하는 지가 중요하죠.
일단 간단한 방식은 파일에 lock을 거는 것입니다. 비주얼 소스 세이프나 소스 오프사이트가 이런 방식입니다.
한 사람이 파일 고치고 있으면 아무도 못 건드립니다. 제가 lock 걸어놓고 깜박 잊고 퇴근했다가 두바이에서 걸려온 전화를 받은 적이 있습니다(실화입니다). -_-;;;
구현은 간단하지만 협업에 불편한 점이 많죠 아무래도...

실제 많이 쓰는 방식은 Version Merge입니다. CVS부터 해서 많은 툴들이 이 방식을 씁니다.
이 방식은 여러 개발자가 동시에 같은 파일을 수정할 수 있다는 장점이 있습니다. 수정이 끝나고 저장소에 체크인할 때, 앞번 개발자가 체크인한 코드와 merge를 해야 되는 거죠. 물론 이 merge 과정은 기본적으로 툴이 제공해주어야 하는 기능입니다만, 같은 부분을 수정했을 경우 conflict가 날 수 있습니다. 이 때는 개발자가 직접 manual merge를 해야겠죠. 그래도 이 방식이 훨씬 편합니다 -_- 하지만 auto merge에 대한 알고리즘 구현이 중요하겠죠.


구 조


대개는 클라이언트-서버 방식으로 구현되었습니다만 최근엔 분산 관리방식의 툴들도 많습니다. 서버가 필요없이 개개인의 작업 디렉토리가 저장소가 되는, P2P에 가까운 방식이라고 할 수 있겠군요.
좀 유명한 것들은 대개 CS 방식이고, 분산 관리도구는 리눅스 커널의 버전 관리 툴은 GIT와 요즘 뜨고 있는 Mercurial, Darcs 등이 있습니다.

CS방식은 굳이 설명할 필요가 없을 것 같고... 분산 관리방식은 서로 변경 내용을 보내주거나 받는 방식으로(보통 pull, push라고 칭하더군요) 공유가 되는데, 직접 개발에 적용해 본 적이 없어서 무어라 평가하긴 힘들지만 쉽지는 않을 것 같은 생각이 듭니다.
즉, 기준이 되는 저장소가 없을 경우 커뮤니케이션 관리가 제대로 되지 않는다면 같은 버그가 여러 번 수정되는 경우가 생길 수도 있을 것 같기도 하군요. 하긴 회사든 오픈 소스든 개발하는 사람들끼리 그 정도도 커뮤니케이션이 안되면 문제가 있는 거겠죠 -_-
공유하는 방식은 http 프로토콜을 쓰기도 하고 email로 패치를 보내주는 방식도 쓰고 다양합니다. 자체 서버를 마련할 수 없는 경우라든가 또 서버가 자주 먹통이 되는 경우 -_- 도움이 많이 되겠지요.


Branch

개발하다 보면 기능 추가를 하거나 등등 '기존 소스 트리를 유지하면서 개발'할 필요가 꼭 생깁니다. 이럴 때에 브랜칭을 하게 되지요. 현재의 소스 트리가 복제된다고 보시면 됩니다. 소스 트리에 '가지'가 하나 더 생기는 것입니다.
물론 유지한다고 해도 기존 트리를 전혀 수정하지 않는단 얘기는 아니지요. 안정성에 문제가 없는 한에서는 기존 소스 트리도 수정은 계속 이루어지고 브랜치는 기능 개발을 계속 하게 됩니다. 그리고 어느 시점이 되면 다시 메인 트리에 브랜치를 머지합니다.
브랜치 기능은 SCM 툴에 반드시 필요한 기능 중에 하나라고 할 수 있습니다.


Tag

소스 스냅샷에 꼬리표(tag)를 다는 기능입니다. 보통은 버전에 따라 달게 되겠지요.
물리적인 특정 시점의(예를 들면 몇월 몇일 당시의 소스) 소스 스냅샷을 얻는 것은 툴에서 제공하므로 대개 어렵지 않지만 논리적인 시점이라면 툴이 판단할 수 없는 문제지요. 1.0-beta를 릴리즈한 시점의 소스라든가 하는 경우는 체크해 놓지 않으면 소스 스냅샷을 찾아 보기는 힘들겠죠.
태그를 설정해 놓으면 태그 이름만 입력하는 것으로 해당 태그 시점의 스냅샷을 얻을 수 있습니다.

이것도 매우 기본적인 기능의 하나입니다만, 가장 유명한 SCM 툴의 하나인 Subversion의 경우는 브랜치나 태그를 모두 지원하지 않습니다. 저장소 내의 소스 디렉토리 카피를 통해서 브랜칭이나 태깅을 할 수 있도록 지원하는데 내부 구조는 모르지만 디렉토리 카피가 저장소 용량을 늘리는 거 같지는 않더군요.


Merge

Locking 방식 툴에서는 필요없는 부분이지만 Version Merge 방식의 툴에서는 반드시 필요한 기능입니다.
하지만 이 기능은 내부적으로 수행되며 Merge 알고리즘도 여러가지가 있다고 하는데 잘 모르겠네요 ^^;


Blame

annoatate라고 부르는게 일반적인지도 모르겠습니다만... 개인적으로는 이 기능을 중요시 여깁니다. 문제 생겼을 때에 범인 추적하기에 좋거든요 -_-;
소스 라인별로 최종 수정된 리비전과 수정자의 id를 표시해주는 기능입니다.


Hook

커밋 전이나 커밋 후에 자동적으로 스크립트를 실행하게 해 줍니다.
커밋 될 때마다 코딩 스타일 툴을 실행해서 코딩 스타일을 맞춘다거나 커밋 전에 유닛 테스팅을 실행한다거나 하면 아주 도움이 되겠죠.


대략 이 정도면 기본적인 기능들인 거 같군요.
제가 써 본 건 사실, CVS, Subversion, 소스 오프사이트(비주얼 소스세이프) 정도 뿐입니다만 요즘은 분산 관리툴이 많이 유명한 거 같아 다음에는 그것들에 관해 정리해 볼까 합니다.

SCM 툴을 쓰더라도 태그나 브랜치 등등을 활용하지 않는다면 기능을 절반도 사용하지 못하는 것이나 마찬가지입니다. 안 쓰신다면 꼭 도입하고, 쓰신다면 기능을 더욱 활용해 보시기 바랍니다.

Trackback 1 And Comment 0

브랜칭의 미학

|

Coding Horror에서 트랙백합니다.

가려운 곳을 제대로 긁은 글이네요. 구슬이 서말이라도 꿰어야 보배라...-_-

어떤 툴이든 사용하는 것만으로 모든 문제가 해결되지는 않습니다. 마찬가지로 버전 관리 도구 또한 쓰기만 한다고 소스 코드의 히스토리가 잘 관리되는 것은 아닌 것 같습니다. 그간의 경험에 비추어 보면요...

위의 글은 특히 브랜치와 머지에 관해 쓴 글인데, 버전 관리도구를 쓰면서 브랜칭을 쓰지 않으면 '왜 버전 관리 도구를 쓰는가'라고 묻고 있습니다. 브랜치 안해도 도움은 되지요, 소스의 변경 이력이 남는다는 점만 해도 매우 크다고 저는 생각합니다.
하지만 반대로 '브랜치를 제대로 하는가'에 대한 내용도 쓰고 있습니다. 이건 쉽지 않은 문제입니다.
글에서는 피해야 할 브랜치와 머지 패턴(anti-pattern)에 대해 나열해 놓았는데 재미있습니다.

머지 기피증(Merge Paranoia) : 두려움에 머지를 하지 않는다.
머지 매니아(Merge Mania) :개발보다 머지에 과도한 시간을 투자한다.
빅뱅 머지(Big Bang Merge) :머지가 개발의 끝단계로 미뤄지고 결국 모든 브랜치를 동시에 머지하면서 큰 혼란이 생긴다.
끝없는 머지(Never Ending Merge) : 머지가 끝날 것 같지 않다 -_- 머지할게 계속 나온다.
잘못된 머지(Wrong Way Merge) : 과거 버전과 머지한다(버전 관리가 잘못되어서 최신 버전이 구분안됨).
브랜치 매니아(Branch Mania) : 브랜치가 너무 자주, 별 이유없이 만들어진다.
끝없는 브랜치(Cascading Branches) : 브랜치들이 메인 브랜치로 머지되지 않고 계속 가지만 쳐 나간다
미스테리 머지(Mysterious Branches) : 누구도 그 브랜치가 왜 만들어졌는지 모른다.
임시 브랜치(Temporary Branches) : 브랜치에 계속 변경을 시도하고 쌓이면서 영원한 '임시' 브랜치가 되어버린다.
가벼운 브랜치(Volatile Branches) :
안정되지 않은 수준의 브랜치가 계속 다른 브랜치에 공유되고 머지된다.
개발 중지(Development Freeze) : 브랜치하고 머지하고 빌드를 만드는 동안 개발 자체가 진행되지 않는다.
베를린 장벽(Berlin Wall) : 브랜치가 작업에 따라 나눠지지 않고 개발자별로 나눠진다 -_-


브랜칭은 소스 관리에서 매우 중요한 요소입니다만 제대로 브랜치를 다루기는 역시 쉽지 않습니다.
어떻게 보면 개발 외적인 문제라 SVN이나 CVS 사용법을 다룬 책은 있어도 브랜칭이나 태깅의 노하우까지 다룬 책은 거의 없습니다.
위의 사항들 중 제가 있는 회사에 해당되는 것도 몇 있군요, 제게 해당되는 거라고 해야 할 지...ㅡㅡ;

여튼 위의 피해야 할 패턴들을 종합해 보면, 브랜칭 목적이 확실해야 하고 메인 브랜치에 반드시 다시 머지가 되는 것을 목표로 해야 합니다.

브랜칭 목적이란 것은 간단할 수도 있고 복잡할 수도 있지만, 최소한 버전업이나 단일 기능 추가를 위한 브랜치가 가장 바람직하지 않나 싶습니다. 크게 보면 같은 의미일 수도 있겠습니다.
대표적인 것은 리눅스 커널이나 FreeBSD 커널의 개발 방식인데 메인 브랜치는 계속 유지하면서 마이너 버전을 릴리즈하고 메이저 버전의 업데이트를 위한 브랜치는 따로 따서 머지 시점까지 계속 개발을 하는 것입니다.

메이저 버전의 업데이트란 것은 구조 변경이나 기능 추가가 중점적이기 때문에 현재 버전의 브랜치에 개발하다가는 릴리즈 버전에 불안정한 버그가 포함될 수 있습니다. 즉, 메인 브랜치는 안정화를 위해 개발력을 투자하고 메이저 버전 업데이트 브랜치는 기능을 추가하거나 구조를 변경하는 작업을 한 후 최종적으로 머지와 테스트를 해서 다음 메이저 버전을 릴리즈하는 것입니다.

단일 기능 추가를 위한 브랜치는 좀 더 직관적입니다. 브랜치 자체를 'thread 지원', '암호화 기능 지원' 등의 단일 기능 추가를 위한 목적으로 따서 개발하고 머지하는 것입니다.

말은 쉬운데, 그렇다면 왜 위에서 열거한 경우가 생기는 것일까요? ㅡㅡ
모든 경우를 경험해 보진 않았지만, 많은 경우는 프로젝트 매니징과 관련이 있습니다. 프로젝트 매니저가 확실한 개발 로드맵을 정하고 개발을 진행시켜야 하는데, 중간에 계속 우선순위가 바뀌거나 한다면 개발하던 브랜치가 쓸모없어지는 경우가 많습니다.
건드리지 않은 채로 브랜치가 오랜 시간이 지나면, 만들었던 사람조차 '내가 왜 이걸 만들었지?'라고 고민하게 되거나, '지금 상황에선 필요없어졌는데..'라거나 '작업했던게 아까우니 일단 놔두자' 이런 식으로 흘러가게 됩니다.

브랜치(branch)란 이름을 누가 붙였는지 모르겠지만, 참 잘 붙인 것 같다는 생각이 드네요. 브랜치도 실제 화분처럼 신경을 안 쓰고 냅두면 말라 비틀어집니다. 그리고 때가 되면 가지치기를 해야 하듯, 머지해야 할 시점에서는 머지가 필요하다는 판단을 내릴 수 있어야 합니다.
물론 머지하기 전에 추가한 내용에 대한 기본적인 테스트가 필요하며, 머지한 후에도 이상이 없는지 테스트를 잘 해보아야하겠지요. 머지 뿐 아니라 개발과 관련된 두려움을 없애는 가장 좋은 방법은 테스트입니다.

모든 것이 다 별개인 것처럼 보이지만 결국 다 이어져 있게 마련입니다.
개발이나 프로그래밍이란 단어에는 코딩 뿐 아니라 위에 언급한 것들까지도 모두 포함되는 것이 맞겠지요. 좋은 개발자가 된다는 것은 역시 쉽지 않습니다.

Trackback 2 And Comment 2
prev | 1 | next