»
S
I
D
E
B
A
R
«
[개발자 역량] 난 디버깅 킹왕짱
Sep 30th, 2009 by Wegra Lee

디버깅을 잘 한다.

나는 과거 종종 그런 얘기를 들은 적도 있고, 또 스스로도 제법 잘 한다고 생각한다. (최근 몇 년간은 직접적인 개발과는 거리가 좀 있는 업무들을 주로 수행해 왔다.)

그런데 ‘디버깅을 잘한다’는 말에는 어떤 의미가 포함되어 있을까.

아무 개념 없이 엉터리로 짠 남의 코드에서 산발적으로 발생하는  미지의 문제를 소스 코드만 추적해서 잘아낼 수 있으면 디버깅을 잘 하는 것일까? 분명 이런 능력은 대단한 것겠지만.. 현실적으로는 ‘운이 좋았다’ 이상을 기대하긴 어렵다. 주변에서도 능력 있는 개발자가 다른 프로젝트 합류 후 ‘내가 할 수 있는 일이 없다’고 푸념하고 경우를 몇 번 보았다. 이유는 몇 년 동안 들여다보던 사람이 아니면 도저히 손 댈 엄두가 안나는 코드를 사용하고 있기 때문이었다. 종속된 모듈과 프로젝트가 많고 덩치도 만만치 않아 새로 깔끔히 만들 수도 없다는 것이다. 동작하는 코드를 새로 만들 시간을 달라는 요청은 관리자들에게 쉽게 묵살당한다.

결국 아무리 능력 좋은 개발자도 대상 소프트웨어의 상태/환경에 따라 발휘되는 능력은 극심한 편차를 보이기 마련이다. 좀 더 정리하여 이야기하면, 커버할 수 있는 임계점 이하까지는 쉽게쉽게 문제를 찾아내지만, 그 한계를 넘어서면 거의 컨트롤이 불가하여 평범한 개발자와 별 차이를 보이지 못하게 된다. 이는 인간이 머릿속에 한 번에 담고 분석/추적할 수 있는 정보량이 그리 많지 않기 때문이다.

중요한 것은 디버깅 대상을 단순 명료하게 유지하는 능력이다. 또는 복잡한 대상을 단순하게 변형하는 능력이다. 구체적인 방법들을 떠올려보자.

  • 컨벤션을 잘 따른다. 예외 상황을 신경쓸 필요가 없으므로 개발자는 context 에 집중할 수 있게 된다.
  • 읽을 수 있는 코드를 작성한다. 해석하는 것과 읽는 것의 차이를 생각해보자.
  • Refactoring 을 통해 코드를 항시 명쾌하게 유지한다.
  • Testability 를 생각해 디자인한다. 문제가 명확하지 않다면 테스트를 통해 하나하나 문제 쉽게 좁히기 쉽다. 디자인이 잘 되어 있다면 모듈 하나하나를 분리해 독립적으로 검증할 수도 있을 것이다. TDD 같은 실천법을 활용하는 것도 적극 추천한다.

이상은 순수한 소스 코드 & 설계의 관점에서의 디버깅 능력 향상 방법들이었다. 유지보수를 위한 지침과 동일하다고 볼 수 있다. 그럼 다른 관점에서는 또 어떤 방법들이 있을까?

  • 다양한 결함 분석 툴을 활용해 잡을 수 있는 문제들을 미리 잡아 놓는다. 사소한 문제들, 혹은 툴이 잘 잡아주는 결함들을 미리 제거해 두면 잠재한 문제의 범위가 좁혀지고, 그만큼 더 집중할 수 있게 된다. (디버깅은 범죄 수사와 마찬가지로, 문제 범위를 좁히고 그에 집중해 파헤쳐보고, 잘못 집었다 싶으면 되돌아가 다른 가능성에 집중에 파헤쳐보는 스타일로 진행된다.)
  • 평소의 좋은 로깅 습관이 디버깅을 높기도 한다. 더욱 효율적인 로깅을 원한다면 역시 좋은 로깅 솔루션을 도입하는 것이 좋다. 주변에 찾아보면 다양한 로깅 프레임워크들을 쉽게 구할 수 있을 것이다. 이들은 로그를 다양한 목적에 맞게 구분짓고, 상황에 맞게 조작/필터링 등을 쉽게 할 수 있도록 도와준다.
  • 디버깅 툴의 파워 유저가 되자. 이러저러한 모든 것을 만족해도 풀지 못하는 문제가 있을 수 있다. 또는 어쩔 수 없이 좋지 않는 코드를 디버깅해야 하는 경우도 많다. 따라서 디버깅 툴을 확실히 활용할 수 있는 능력은 기본으로 갖춰두어야 한다.
  • 개발툴/언어 외적인 보조 방법을 활용한다. 예를 들어 aspect 언어를 활용할 줄 안다면 디버거로 쉽게 잡아내지 못하는 복잡한 상황까지도 아주 간단히 연출해낼 수 있다.

이상은 소스 코드 외적인 방법이었지만, 개인이 충분히 할 수 있는 것들이다. 그럼 마지막으로 소셜 개발자라면 또 어떠한 방법들을 생각해볼 수 있을지 나열해보겠다.

  • 유사 도메인의 구루, 혹은 전문 커뮤니티 활용한다.
    오늘날 대부분의 프로젝트는 다수의 외부 라이브러리/플랫폼을 활용하기 때문에, 이 능력의 중요성은 과거보다 훨씬 커졌다. 내가 겪는 대부분의 문제는 누군가 이미 겪어서 그 해결책(혹 ‘어쩔 수 없다’일지라도)이 공개되어 있다. 대답을 찾지 못하더라도 질문을 올리면 늦어도 몇 일 내에 만족할만한 답을 찾을 수 있을 것이다.
    테스트 방법이나 설계에 대한 조언도 쉽게 구할 수 있다. 물론 앞서의 경우보다는  훨씬 복잡한 이슈라 자신이 처한 상황을 명확히 기술해주어야 좋은 답을 얻을 가능성이 그만큼 높아진다.
    중요한 부분이 아니라면 소스 코드를 공개해
  • 만든 제품에 대해 피드백을 받을 수 있는 커뮤니티를 만들고, 가능하다면 오픈소스화 한다.
    직접 디버깅 하는 것만이  꼭 능력은 아니다. 더 궁극적인 목적은 결함 없는 제품을 만드는 것이 아닌가? 그러려면 프로젝트가 남의 관심을 받을 만큼 충분히 유용해야하고, 그들의 요구사항을 적극 반영하며 기여자(contributor)들과 지속적으로 좋은 관계를 유지해야 한다.

디버깅 하나 얘기하면서 참 많은 것을 훑었다. 오버라고 생각할 수도 있겠지만, 개발이라는 것이 그리 딱딱 떨어지는 것이 아니고.. 이것이 현실이다. 오히려 위에 나열할 것 외에도 수많은 요소들이 훌륭한 디버거를 만드는 관여될 것이 분명하다.

자!! 그럼 지금까지 나온 좋은 디버거로서의 자질은 정리해보자.

  • 명확하고 논리 정연한 코드 작성 능력
  • 꾸준한 코드 관리
  • Testable 디자인 능력
  • 다양한 분석 툴 활용 능력
  • 좋은 로깅 습관 & 로깅 툴 활용 능력
  • 디버깅 툴 활용 능력
  • 주변 전문가, 커뮤니티, 웹 상의 정리된 지식 활용 능력
  • 외부 기여자를 끌어모아 적극적인 피드백을 이끌어 내는 능력
TDD, Refactoring and Scrum – Part II
Sep 9th, 2009 by Wegra Lee

내가 지금까지 접해본 여러 이론/실천법 들을 통틀어 가장 맘에 드는 것들을 세 가지 고르라면 TDD, Refactoring, Scrum, 이렇게 세 가지를 뽑겠다. (우리 조직에선 이 중 단 하나도 하지 않고 있어서 참으로 답답하고 안타깝다.) 다른 사람들과는 좀 다른 관점일 수 있겠는데, 이들에 애착이 생기는 내 나름의 이유는 간략히 정리해본다.

  • Part I – TDD
  • Part II – Refactoring (this article)
  • Part III – Scrum (not available yet)

Refactoring – Refactoring은 현재의 잘못된 점이나 부족한 부분을 식별하여 더 나은 형태로 개선하는 작업이다. 따라서 Refactoring 은 일종의 회고이며, 그 주된 관점은 설계/코드의 효율성, 가독성, 명확성 등이다. 사람이나 조직이 회고를 통해 교훈을 얻고 성장하듯, 개발자도 Refactoring 을 통해 역량을 키워나간다. 여건이 되지 않으면 혼자서라도 틈틈히 수행해야 하며, 다행히 지도해줄 경험 많은 동료가 함께한다면 그 효과는 배가된다. 팀의 리더라면 팀원간의 이런 교류가 자연스레 일어날 수 있도록 이끌어 주어야 한다.

Refactoring은 개발 기간 내내 리듬을 가지고 정기적으로 수행되어야 한다. 리펙토링 문화가 충분히 자리잡지 못했다면 프로세스에 명시해두는 것이 좋다. 시점은 매 반복 주기(iteration/milestone)가 끝나고 다음 주기가 시작되는 시점이다. 새로운 기능을 넣기 전에 기반을 단단히 다진다거나, 구조적 문제를 조기에 다잡아 추후 대규모 수정을 예방한다는 점도 물론 중요하지만, 사람(개발자)의 역량 성장 측면에서도 반드시 요구되는 프로세스이다.

배우고 경험하고 배우고 경험하고.. 두 과정이 주기적으로 반복되어야 머리로 익힌 것이 체화되고, 그것이 실생활에서 어떤 가치가 있는지 진정한 의미를 깨닫게 된다. 처음에 좋아보였던 것도 생각지 못했던 숨은 이슈나 과소 평가했던 측면 때문에 실제로는 역효과가 더 큰 경우도 많다. 또한 체험 없이 계속해서 머리로만 익히다 보면 모든 것이 쉽고 단순해 보이는 경향이 있다. 이렇게 해서 다음 리펙토링을 수행할 때에는 이전 수행 시보다 향상된 시각으로 구조를 바라볼 수 있게 된다. 설계와 코드를 보는 눈이 향상되고, 시행착오가 줄어들고, 다양한 경험을 통해 확신을 가질 수 있다. 주기적인 Refactoring은 프로젝트가 진행될 수록 Refactoring의 품질과 그것을 수행하는 개발자 역량을 함께 성장시킬 수 있는 멋진 제도적 장치가 될 것이다.

Refactoring 시 주의점

리펙토링 시 가장 신경써야할 부분은 역시 side effect 다. 때문에 전문 툴 활용과 풍부한 테스트 케이스가 준비가 큰 도움을 준다. 툴의 Refactoring 지원 정도는 언어별로 편차가 심하다. Small Talk, Java 언어는 Refactoring 이 지원되지 않는 툴은 오래전에 자취를 감췄을 정도로 대중화되어 있고, C#, Visual Basic 등은 중간 정도.. C/C++ 계열은 아직 많이 부족하며 발전 속도도 더디다.

툴이 해주는 일은 다양한 리펙토링 기법들을 마우스 클릭 몇 번으로 관련된 모든 코드를 자동 변경해주는 편리함과, 이 때 발생할 수 있는 구조적 충돌을 사전 검증하여 side effect 을 최소화시켜주는 효과가 있다. 소프트웨어 규모가 커지면 수십명이 일주일 동안 해야할 변경량을 한 사람이 반나절 만에 처리할 정도로 극적인 효과를 볼 수도 있다.

툴이 구조적인 side effect를 예방해준다면, 테스트 케이스는 기능적인 side effect 를 예방해준다. 테스트 케이스가 충분치 않다면 변경의 잘못된 영향을 먼 훗날에야 발견하게 되고, 무엇이 그 원인이었는지 파악하기 어렵게 된다.

Refactoring 과 TDD
테스트의 대표 주자는 역시 TDD 이다. 현실적으로 거의 불가능하지만, TDD 를 100% 잘 따랐다면 작성된 코드 중 테스트 케이스가 커버하지 못하는 영역은 존재하지 않는다. 따라서 Refactoring 을 가장 안전하게 하기 위한 좋은 지침은 TDD 를 잘 따르는 것이다. 역으로 TDD 의 과정에서 새로운 테스트 케이스(요구사항)가 추가되면, 그 케이스를 만족시키기 위해 기존 코드를 Refactoring 해야한다. 이렇든 이 둘은 거의 바늘과 실 관계이다. 다만 Refactoring 없는 TDD 는 그 효과가 급감하지만, TDD 없이도 테스트 케이스는 작성할 수 있으므로 Refactoring 은 독자적으로도 충분한 가치가 있다.

Grand Central Dispatch
Sep 8th, 2009 by Wegra Lee

평소 기술 동향에 관심이 많아 Parallel Programming 을 빨리 익혀둬야겠다 생각한 지는 벌써 1년도 훨씬 지난 것 같은데, 마땅한 기회를 잡지 못해서 자료만 모으고 있었다. 그러다 마침 Snow Leopard 에서 Grand Central Dispatch (이하 GCD)라는 멋진 기술을 제공한 것을 계기로 몇 일 동안 이러저런 자료들을 살펴보았다. 처음엔 기본적인 개념 정리까지 해볼까 하였으나, 현재로썬 단순 번역 정도에서 그칠 듯 싶어 마음을 바꿔먹었다. 오늘은 운을 띄우는 정도에서 몇 자 적어보고.. 더 깊이 있는 지식과 경험을 쌓으면 보다 전문적인 글을 적어보겠다.

CPU 가 클럭 경쟁에서 멀티코어 형태로 그 진화 방향이 변화하였고, GPU 의 성능이 CPU 를 능가하기 시작하면서, 그 막강한 프로세싱 파워를 그래픽 외적인 목적으로도 활용코자 하는 노력도 몇 년 전부터 꾸준히 진행되어 왔다. 멀티 코어 CPU 와 GPU 의 공통적인 특징은  바로 복수의 프로세싱 엔진(코어)를 갖음으로써 여러 개의 서로 다른 연산을 병렬로 처리할 수 있다는 점이다. Parallel Programming 은 이런 다중 코어 환경에서 코어들을 최대한으로 활용하여 프로그램의 성능을 향상시키고자 하는 프로그래밍 기법을 일컷는다.

서버 분야에서는 멀티 코어 이전부터 멀티 프로세서 환경이 일반화 되어 있기 때문에 Parallel Programming 의 역사는 상당히 깊다. 자연히 GCD 는 갑자기 혜성처럼 나타난 별천지 기술은 아니다. 그리고 기존 상식을 뛰어넘는 혁신적인 아이디어도 보이진 않는다. 다만 서버 분야에서부터 적어도 십수년간 쌓아온 노하우를 애플 식으로 OS X 플랫폼에 멋지게 녹여낸 것이다. 그럼 애플 외의 다른 경쟁 데스크탑 플랫폼에서의 상황은 어떠할까?

.NET 은 곧 등장할 Windows 7 부터 4.0 으로 버전업되며, .NET 4.0 의 큰 특징 중 하나로 Task Parallel Library (TPL) 탑재가 있다. MS 도 바보가 아닌 이상 병렬화라는 시대 흐름을 놓칠 리 없고, 애플과 비슷한 시기에 비슷한 문제를 해결하려는 나름의 솔루션을 내놓는 것이다. Java 역시 곧 등장할 JDK 7 에 Fork/Join Framework 을 포함한 JSR166y 를 추가하여 병렬 환경 지원을 강화하고 있다.

이렇듯 Parallel Programming은 이제 거스를 수 없는 시대의 흐름이고, 어플리케이션이 이를 얼마나 잘 활용하느냐에 따라 수십배의 성능 차이를 보이는 날이 곧 도래할 것이다.

다시 애플의 GCD 로 돌아가보자. 내가 아직 전문 지식이 부족한 관계로 정확한 평가는 불가능하지만, 현재의 얕은 지식만을 바탕으로 봤을 때 GCD 의 큰 장점은 아래 정도이다.

  1. 병렬 실행 환경을 OS 자체에 매끄럽게 녹여내어 이론적으로 가장 높은 효율성을 보장할 수 있다. GCD 런타임이 시스템 서비스와 어플리케이션 전체 상황을 종합 고려하여 최상의 성능을 발휘할 수 있도록 스케줄링한다.
  2. OS X 의 주 개발 언어인 C/C++/Objective-C 모두에서 사용 가능하다. 즉, native 어플리케이션도 몇 라인 수정하는 것으로 멀티 코어의 장점을 십분 활용할 수 있다.

이 글은 관련 자료 중 쓸만한 링크들을 남겨놓는 것으로 마무리 하겠다. 나중에 직접 작성해볼 기회가 생기면 코드 수준에서의 간단한 설명과 성능 테스트 결과 정도를 포스팅할 생각이다.

»  Substance: WordPress   »  Style: Ahren Ahimsa