»
S
I
D
E
B
A
R
«
책은 어떻게 써? (첫 책을 꿈꾸는 개발자를 위한 ‘엉성한’ 집필 요령)
Jul 28th, 2015 by Wegra Lee

최근 한 지인 개발자가 책을 쓰고 싶다며 ‘일반적인 책 집필 방법 좀 알려달라’는 상당히 추상적인 질문을 던졌다.
러프한 질문이라 러프하게 답할 수밖에 없는데..
어쨌든 같은 궁금증을 가진 사람이 또 있을 듯해서 여기에도 옮겨본다.
깊은 고민 없이 휘갈겨서 허점이 많을 테니 양해를.. ㅎㅎ
질문자가 개발자라 개발자가 이해하기 쉽게 작성해 보았다.
뭐, 소프트웨어 제품 만드는 거랑 비슷하고 보시면 될 거 같아요.
  1. 시장을 분석하고(시장 규모, 트랜드, 경쟁 서적, 잠재 독자가 어떤 걸 원하는지)
  2. 컨셉을 잡고(책 주제, 독자층, 차별점)
  3. 설계를 하고(목차 잡기, 자료 조사)
  4. 구현하는 거죠(집필).
시장 분석은
  • 분야 경쟁서가 있다면 아마존 랭킹이나 예스24 판매지수 등으로 시장 크기와 트랜드를 꽤 정량적으로 알 수 있어요.
  • 경쟁서가 없다면 정성적으로 가야겠죠. 업계 기술 트랜드라거나..
컨셉 잡을 때는
  • 분야 1등을 노릴 것이냐, 차별화해서 시장을 가를 것이냐 고민해보시고,
  • 대상 독자가 초 -> 중 -> 고로 갈수록 판매량은 급격하게 떨어지니 참고하시고요.
  • 대표적인 전문서 유형으론 바이블, 레퍼런스, 따라하기, 주제별 심화 내용, 에세이 등이 있습니다.
  • 책 제목, 부제, 홍보 카피, 책 소개 문안(3~5줄 정도)도 꼭 고민해보세요. “나 이런 책을 쓰고 있다”고 남에게 이야기할 수 있을만큼 해주세요. 책의 정체성이 확립되어 이후 단계에서 등대 같은 역할을 해줄 겁니다.
설계 단계에서는
  • (시스템 워크플로 그려보기)
    대상 독자의 수준과 관심사를 고려해서 차근히 단계를 정하고
  • (필요한 모듈을 추출하고 핵심 인터페이스 정하기)
    목차는 장과 절 수준까지는 구체화하는 게 좋습니다
  • (프로토타이핑)
    각 장과 절에서 무슨 이야기를 할 지 3~5줄 내외로 요약해 보세요. 시작 문단과 끝 문단을 적어보는 것도 좋습니다.
구현 단계에서는..
  • 설계 단계에서 비워놓은 것들을 하나씩 채워야죠. ^^ 요건 요령이 너무 많고, 사람마다 현 수준이나 성향이 다양해서 짧게 정리하기엔 무리가 있습니다. case by case라 직접 쓴 원고로 편집자나 주변 글 잘 쓰는 분께 피드백 받는 게 가장 좋을 거에요.
  • 러프하게는 글쓰기 관력 책도 많고, (IT인들이 워낙 번역된 글을 많이 접해서) 역자를 위한 책도 우리글 잘 쓰기에 큰 도움이 됩니다. 개인적으론 일반 글쓰기 책보다 역자용 책이 더 좋더군요.
  • 코딩 잘하는 요령과 비슷한 거죠. <클린 코드>만 해도 550 페이지네요. ㅎㅎ
마지막으로..
집필 초보자라면 초기 단계부터 전문가와 논의를 해야 재집필하거나 노고를 헛되이하는 걸 막을 수 있습니다.
‘메타프로그래밍’이란?
Feb 27th, 2014 by Wegra Lee

메타?

나중에 더해져서 다른 개념을 보강 혹은 완성하는 것
A concept which is an abstraction from another concept, used to complete or add to the latter.

메타 데이터?

다른 데이터를 기술하는 데이터

metadata

책이라는 ‘실체를 훼손하지 않고’ ‘언제건’ 정보를 ‘더하거나 수정’할 수 있다.
‘실체에 접근하지 않고도’ 메타 데이터만으로 대상을 다룰 수 있다.
예> 분류, 검색, 정렬 등

메타 프로그래밍?

프로그래밍에 메타 정보를 활용하는 것!
즉, 프로그램 본체 작성 후에 새로운 기능을 추가하거나 다른 용도로 사용할 수 있게 정보를 제공할 수 있다.

활용 예>

* 자바 어노테이션 (참고 – JUnit 4, 60초만에 익히기)
* AOP(Aspect-oriented programming): 로깅, 동기화, 권한 확인 등
* C++ 템플릿 메타프로그래밍
* Ruby: 런타임에 객체 인스턴스에 새로운 메서드 추가

장점

부차적인 요소 혹은 변경될 소지가 있는 요소를 메타 정보로 추출하여 핵심 로직만 남겨둘 수 있다.
따라서 소스 코드의 가속성과 프로그램의 유연성이 높아진다.

단점

자칫 전체 로직의 연결 고리 일부가 사라져서 프로그램을 이해하기 어렵게 만들 수 있다.

단일 책임 원칙: 그 단순함과 복잡함
Feb 10th, 2014 by Wegra Lee

(원문) SRP: Simplicity and Complexity

Effective Unit Testing의7.1.2절에서 인용한 블로그 글이다.

단일 책임 원칙: 그 단순함과 복잡함

단순한 것이 차차 복잡해지는 것이 아니다. 오히려 그 반대다. – 알랜 퍼리스(Alan Perlis)

SOLID 원칙 중 하나인 “단일 책임 원칙(SRP, The Single Responsibility Principle)”은 내가 가장 좋아하는 객체지향 설계 원칙 중 하나다. 나는 이로부터 단순함과 복잡함을 동시에 발견할 수 있었다. 이 원칙을 알게 된 게 수 년 전이고, 직접 관련 글을 써본 지도 일 년이 넘었다. 하지만 이를 실무에 적용하기란 여전히 쉽지만은 않다. 수년간 여러 개발자에 이 원칙을 전파하면서 흥미로운 사실을 발견했다. 모두가 이 원칙의 의미는 이해하고 있지만, 막상 코딩할 때에는 까맣게 잊어버리거나 적용하는 법을 몰라 헤매는 것이다. 그래서 이 문제를 바라보는 나의 관점과 지금껏 겪어왔던 경험을 이야기해보려 한다.

외적 측면 (참고: 책에서는 ‘외면’이라 번역함)

모든 클래스와 메서드는 단 하나의 역할만 수행해야 한다.

이것은 내가 “외적 측면”이라 부르는 것으로, 이름이 중요한 상황이다.

외적 측면은 새로운 코드를 작성할 때 주로 고려된다. 무엇을 하는 코드인지 생각해본 후, 클래스나 메서드를 작성하고, 새 코드가 하는 일을 잘 표현하는 이름을 지어준다. 코드를 읽을 때도 외적 측면이 작용한다. 이름만 봐도 클래스나 메서드가 무슨 일을 하는지 바로 알 수 있어야 한다.

여기까지 이해하는 데 아무런 무리가 없으리라 믿는다.

그렇다면 이처럼 이해하기 쉬운데도, 사람들은 왜 이를 잘 지키지 않을까? 왜 적절한 클래스와 메서드를 찾으려 수천 줄의 코드 속에서 헤매고 있는 걸까? 그럴싸한 이유가 몇 개 떠오른다. 아마도 우리는 작명에 소질이 없나 보다. 혹은 너무 일반적이거나 광의적인 이름을 써서 너무 많은 일을 한꺼번에 처리하고 있을지도 모른다. 그것도 아니면 그냥 신경 쓰지 않는 것일 지도.

내적 측면 (참고: 책에서는 ‘내면’이라 번역함)

클래스와 메서드를 수정해야 하는 이유는 오직 하나뿐이어야 한다.

이는 내가 “내적 측면”이라 칭하는 것으로, 단일 책임 원칙의 또 하나의 (자주 잊히는) 측면이다.

내적 측면은 기존 코드를 변경하거나 새로운 코드를 집어넣으려 할 때 고려된다. 다시 말해, 각 클래스와 메서드가 무슨 일을 하는지 파악해야 하는 상황이다. 이때 분석해야 할 코드량이 예상보다 훨씬 많아 좌절할 때가 많은데, 주원인은 클래스나 메서드가 원래 해야 할 일보다 훨씬 많은 것을 처리하고 있기 때문이다.

하지만 외적 측면보다 내적 측면에 집중하면 단일 책임 원칙을 적용하기가 한결 쉬워진다. 즉, 역할에만 신경 쓰지 말고, 클래스나 메서드를 변경해야 할 이유가 몇 가지나 되는가를 항시 고민하자.

그렇다면, 언제 어디서 일이 틀어지는 것일까?

노트: 대게 개발자가 TDD와 리팩토링을 하지 않는 조직일수록 단일 책임 원칙에 어긋나는 사례가 많다.

생각해보자. 경험상 단일 책임 원칙에 어긋나는 사례 대부분은 시스템 인터페이스에 가까운 클래스와 메서드에서 발견되었다. 예를 들면, 웹 애플리케이션의 거대한 컨트롤러나 액션 클래스, 스윙 애플리케이션의 거대 이벤트 핸들러, 이벤트 기반 시스템에서 메시지 처리를 담당하는 거대한 메서드 등이 있다.

이는 시스템 인터페이스에 가까운 클래스와 메서드는 더 광범위하고 일반적인 역할을 담당하기 때문이다. 이런 메서드는 수많은 비즈니스 규칙이나 복잡한 워크플로우를 관장하는 경우가 제법 많다.

거래 정보를 담은 거대한 XML 파일을 입력받는 시스템을 상상해보자. 그리고 이를 처리하는 첫 메서드는 TradeService 클래스의 “processTrade(tradeXML)”라고 해보자. 이 메서드의 역할이 무엇인가? 바로 거래를 처리하는 것이다. 그렇다면 이름은 적절한가? 이 시스템은 입력받은 거래(trade)를 처리(process)하길 원하니 첫 메서드의 이름으로 processTrade는 적절해 보인다.

다른 예를 보자. 인터넷 쇼핑 사이트에서 고객이 상품 몇 개를 장바구니에 담고, 지불 정보를 입력하고, “주문” 버튼을 클릭했다. 그렇다면 뒷단에서는 주문 발주를 위해 대략 placeOrder(order) 정도의 메서드를 호출할 것이다. 나쁘지 않다.

생각 발전시키기

일반적으로, 시스템 인터페이스에 가까운 코드일수록 더 폭넓고 일반적인 역할을 담당하는 경향이 있다. 반면, 시스템 인터페이스에서 멀어질수록 더 좁고 특수한 역할을 담당하게 된다.

앞의 두 예에서, processTrade와 placeOrder 메서드는 단 하나의 역할만 수행한다고 주장할 수 있다. 전자는 입력받은 거래를 처리하고 후자는 고객의 주문을 발주한다. 그래서 단일 책임 원칙의 외적 측만을 고려하는 개발자라면 거리낌 없이 관련된 코드 모두를 그 메서드 안에 욱여넣을 것이다.

문제는 거래 처리와 주문 발주가 심히 복잡한 작업이라는 데 있다. 복잡한 과정을 거쳐야 하고, 수많은 비즈니스 규칙과 요구사항을 만족하게 하기 위한 수백 수천 줄의 코드를 작성해야 할 것이다. 그러니 이 많은 코드를 한 메서드에 욱여넣는 것은 단일 책임 원칙을 명백히 위반할 뿐 아니라, 어리석기까지 한 일이다.

단일 책임 원칙을 만족하는 코드를 만들려면, 변경 사유가 오직 하나뿐이어야 한다. 이는 다음과 같이 발전된 생각을 이끌어내 준다.

일반적으로, 시스템 인터페이스에 가까운 클래스일수록 더 많은 것을 위임(delegation)한다. 반면, 시스템 인터페이스에서 멀리 떨어진 클래스일수록 위임할 것이 적어진다.

전통적인 자바 웹 애플리케이션의 컨트롤러가 좋은 예다. 사용자 인터페이스와 가까운 컨트롤러는 폭넓은 역할을 담당하며 비즈니스 로직은 모두 다른 객체에 위임한다. 컨트롤러는 단순히 흐름만 제어할 뿐이다. 정 반대로, 매우 특수하고 제한된 역할만 수행하는 DAO(Data Access Object)는 일거리를 다른 클래스에 위임하는 경우가 거의 없다. 그 중간에 위치하는 서비스는 자신의 비즈니스 로직을 처리하지만, 종종 다른 협력 객체에 작업을 위임하기도 한다. 서비스는 컨트롤러보다는 좁고 DAO보다는 광범위한 역할을 처리하는 게 보통이다. 어쨌든, 각 클래스와 메서드는 단일 역할만을 담당한다.

다르게 질문하기

다른 개발자에게 맨토링해주거나 함께 짝(pair) 프로그래밍을 하며 한 메서드 안의 코드량이나 클래스 안의 메서드 수를 가지고 논쟁을 벌일 때가 많다. 단일 책임 원칙의 외적 측면만을 근거로 내세운다면 코드가 하는 일이 너무 많다는 걸 잘 인정하지 못하는 개발자가 많을 것이다. 그래서 내적 측면이 중요하다는 걸 깨달았다. 이제는 메서드나 클래스가 맡은 역할이 몇 개인가를 묻는 대신, 수정해야 하는 이유가 몇 가지나 되느냐고 묻기 시작했다.

지속적 통합(Continuous Integration) 구성 사례
Jun 7th, 2011 by Wegra Lee

이번엔 지속적 통합 사례를 하나 정리해보겠다. (지속적 통합의 개념 설명은 이곳에..)

Components and Basic Workflows

이번에 구성해본 지속적 통합(CI) 환경의 구성 요소는 다음과 같다.

  • CI (Continuous Integration) 툴: IBM Rational Team Concert (RTC)
  • 소스 관리: IBM Rational Team Concert
  • 빌드 스크립트: Apache Ant
  • (참조) Apache Maven

비록 RTC라는 상용 툴을 사용하고는 있지만, 이 글에서 다루는 대부분의 내용은 개념적인 것이라, 다른 툴(예: Hudson, TeamCity, CruiseControl)을 사용할 때도 그대로 적용/응용할 수 있다.

전체 시스템을 그림으로 나타내면 대략 다음과 같다.

ci

RTC 서버의 다양한 기능 중, 여기에서는 소스 관리와 빌드 관리, 그리고 웹 UI 정도이다. 거시적인 작업 흐름은 다음과 같다.

  1. 개발자가 변경 내용(change-set)을 소스 저장소에 전달한다.
  2. RTC 서버의 빌드 모듈이 이를 인식해 적당한 빌드 엔진에 할당한다.
  3. 빌드 엔진은 소스 저장소로부터 빌드에 필요한 데이터를 내려 받아 Ant 빌드 스크립트를 수행한다.
  4. Ant 빌드 스크립트는 빌드를 수행하고 산출물을 개발 서버 및 API 서버에 배포한다.
  5. 빌드 엔진은 빌드 결과 및 과정은 빌드 서버에 알리고, 서버는 개발자 PC에 푸시한다.

개발자나 프로젝트 관련자들은 이런 모든 과정/결과를 언제든 전용 Eclipse UI나 Web UI를 통해 확인할 수 있다.

또한, 어떤 빌드 엔진을 사용할 지, 어떤 스크립트를 사용한 지 등은 모두 configuration 가능하다.

Project Directory Layout

여러 팀, 다양한 과제에 걸쳐 일을 효율적으로 진행하려면 프로젝트 구성부터 일관적으로 유지하는 것이 좋다.

Ant는 비록 산업 표준 빌드 툴이지만, 프로젝트 구성에 대한 표준 규약은 제공하지 않는다. 때문에 담당자 취향만큼이나 다양한 구성이 존재하며, 그 구성을 정하고 관리하는데에만 상당한 고뇌와 노력이 소요된다. 그리고 재활용도 쉽지 않다. 바로 이 문제를 타파하고자 나온 오픈소스 프로젝트로 Maven이란 것이 존재한다. Maven 개발자들은 프로젝트의 구성에 관련된 모범 사례(best practice)들을 집대성하고자 하였다. 무분별한 컨피규레이션 허용보다는 잘 정의된 모범 사례를 따른는 것을 원칙으로 삼은 것이다(Convention over Configuration). 물론 그 결과가 이상적으로 완벽하진 않지만, 상당수의 프로젝트에 적용하는데 큰 무리가 없을 것이다.

어쨌든, 본 예제에서는 Ant를 사용하지만 Maven의 이상과 결과를 상당부분 따르고 참조할 것이다. 물론 Ant이기 때문에 언제든 어렵지 않게 수정 가능하다.

그래서 내가 구성한 기본 구성은 다음과 같다.

  • src/main/java – 제품 소스 코드
  • src/main/resources – 제품에 포함될 리소스
  • src/main/config – 제품 설정 정보
  • src/main/webapp – 웹 애플리케이션 소스
  • src/test/java – 테스트 소스 코드
  • src/test/resources – 테스트에 필요한 리소스
  • lib/main – 제품 수행에 필요한 라이브러리
  • lib/test – 테스트에 필요한 라이브러리 (junit, mokito  등)
  • tools – 팀내 공용 툴 (예: FindBugs, CheckStyle, Code Pro Analytix 등)
  • build.xml – Ant 빌드 스크립트
  • build.properties – Ant 빌드 스크립트용 커스텀 프로퍼티 파일
  • build-jazz.xml – RTC/Jazz용 빌드 스크립트(build.xml을 확장함)
  • LICENSE.txt – 제품 라이선스 정보
  • README.txt – readme 파일

참조함 Maven의 표준 디렉터리 구성과 크게 다르지 않다. 간소화를 위해, 크게 필요 없다고 생각되는 filters, assembly, site, NOTICE.txt 를 제거하였고, lib과 tools가 추가되었다.

lib이 추가된 이유는 Maven이 종속성 자동 관리 기능이 포함된데 비해 Ant는 직접 필요할 라이브러리를 관리해야 하기 때문이며, tools 는 개발팀 내 함께 쓰는 유용한 도구와 그 설정 정보를 공유하기 위함이다.

빌드 스크립트는 총 3개의 파일로 구성된다. build.xml 은 메인 빌드 스크립트이며, build.properties에는 그 중 사용자 정의 속성을 담아, 상황에 맞게 설정하여 빌드할 수 있게 하였다. 마지막의 build-jazz.xml 은 build.xml을 확장(import)하여 RTC/Jazz에 종속된 기능을 추가로 수행하기 위해 추가하였다. 즉, build-jazz.xml를 제외한 두 파일은 RTC/Jazz와 완전히 독립적이어서 어떤 환경에서건 그대로 재활용할 수 있다.

스크립트의 속 내용은 조금 후에 살펴보기로 하고, 빌드 과정에서 생성되는 디렉터리 레이아웃에 대해서 먼저 살펴보자.

  • target/classes – 제품 소스를 컴파일한 클래스 파일들 & 리소스
  • target/test-classes – 테스트 소스를 컴파일한 클래스 파일들 & 리소스
  • target/reports/unit-test – 단위 테스트 결과 리포트 (XML 포맷)
  • target/reports/unit-test/html – 단위 테스트 결과 리포트 (HTML 포맷)
  • target/reports/integration-test – 통합 테스트 결과 리포트 (XML 포맷)
  • target/reports/integration-test/html – 통합 테스트 결과 리포트 (HTML 포맷)
  • target/reports/findbugs – FindBugs 수행 결과 보고서
  • target/reports/checkstyle – CheckStyle 수행 결과 보고서
  • target – 빌드 산출물 루트 겸, package 된 제품 바이너리 등 최종 산출물

특별한 설명은 필요 없으리라 본다. 그렇다면 이제 Ant 빌드 스크립트의 내용과 빌드 단계에 대해 알아보기로 하자.

Ant Build Script and Build Lifecycle

Ant 빌드 스크립트는 빌드 타깃(target)과 타깃간 종속성(선행 타깃 정의)과 타깃에서 실행해야할 실제 작업을 정의한다. 빌드 라이프사이클 역시 Maven의 그것을 기반으로 간소화한 후 약간 보강하였다. 다음은 build.xml에 정의된 타깃들을 라이프사이클에 따라 설명한 것이다.

  1. compile – 제품 소스 코드를 컴파일한다.
  2. test-compile – 테스트 코드를 컴파일한다.
  3. unit-test – 단위 테스트를 수행한다.
  4. package – 제품 컴파일 결과를 배포 형태로 패키징한다.
  5. integration-test – 통합 테스트를 수행한다.
  6. code-analysis – 정적 코드 분석을 수행한다. (FindBugs, CheckStyle)
  7. deploy – 패키징한 결과를 개발 서버 및 API 서버로 배포한다.

몇 가지만 살펴보겠다.

먼저, code-analysis가 Maven에 없는 새로 추가된 단계이다. 이 단계에서는 FindBugs, CheckStyle 등의 정적 코드 분석 툴을 이용하여 제품 소스 코드의 잠재적 결함과 코딩 규약 부합 여부를 검사한다. code-analysis 단계 외에는, 실패 시 다음 단계를 계속 진행할 수 없다.

unit-test 단계에서는 수행시간이 짧은 단위 테스트들을 실행한다. 통합 테스트 케이스와 시간이 오래 걸리는 테스트 등은 뒷쪽의 integration-test 단계에서 수행시킨다.

마지막 deploy 단계에서는 완성된 바이너리를 개발 서버로, 최신 API 문서를 API 서버로 배포한다.

변경 가능한 사용자 속성으로는 다음과 같은 것들이 있다.

  • product.name  - 제품명
  • product.version – 제품 버전
  • main.class – 실행 클래스명: jar 파일의 Manifest 파일에 추가됨
  • compile.deprecation – javac 컴파일 옵션
  • compile.debug – javac 컴파일 옵션
  • compile.optimize – javac 컴파일 옵션
  • compile.source – javac 컴파일 옵션
  • compile.target – javac 컴파일 옵션
  • proxy.host – 프락시 주소 (프락시 안에 갖힌 네트워크에서 수행될 때)
  • proxy.port – 프락시 포트 (프락시 안에 갖힌 네트워크에서 수행될 때)
  • deploy.binary.host – 패키징된 바이너리를 배포할 호스트 주소
  • deploy.binary.user – 호스트 로그인 계정
  • deploy.binary.passwd – 호스트 로그인 패스워드
  • deploy.binary.keyfile – 호스트 로그인에 필요한 key 파일 위치 (xxx.pem)
  • deploy.binary.dir – 바이너리를 복사해 넣을 호스트 내의 디렉터리 경로
  • deploy.api.host – 최신 API를 배포할 호스트 주소
  • deploy.api.user – 호스트 로그인 계정
  • deploy.api.passwd – 호스트 로그인 패스워드
  • deploy.api.keyfile – 호스트 로그인에 필요한 key 파일 위치 (xxx.pem)
  • deploy.api.dir – 바이너리를 복사해 넣을 호스트 내의 디렉터리 경로 (웹 서버 혹은 파일 서버)

보는 바와 같이 소스 코드 디렉터리 구조, 산출물 파일 이름과 같은 정보는 따로 설정할 수 없도록 제안하고 있다. 이유는 초반에 언급한 Maven의 설계 원칙(Convention over Configuration)을 좀 더 강요하기 위함이다.

물론 build.xml의 내용을 보면 관련 정보를 속성으로 제공하여, 꼭 필요한 경우 쉽게 변경할 수 있다.

마지막으로 build-jazz.xml 파일을 살펴보자.

이 파일은 build.xml 을 확장하여 RTC/Jazz 빌드 서버에서 사용할 특화 타깃을 정의하고 있다. RTC/Jazz 빌드 기능에 특화된 만큼, 이 스크립트를 개발자 IDE에서 실행하려 하면 필요한 파일이 없다면서 에러를 발생시킬 것이다. 물론 몇 가지 설치/설정으로 가능케할 수 있지만, 별다른 이점은 없으니 Jazz 빌드 서버에 맡기기로 하자.

기본적으로는 다음의 네 가지 타깃이 제공된다.

  • package-jazz – build.xml의 package 단계까지 수행한 후, 산출물과 보고서를 RTC/Jazz에 등록한다. 단위 테스트 보고서와 패키징된 바이너리가 이에 포함된다.
  • integration-test-jazz – build.xml의 integration-test 단계까지 수행한 후, 산출물과 보고서를 RTC/Jazz에 등록한다. 위 결과에 통합 테스트 결과가 추가된다.
  • code-analysis-jazz – build.xml의 code-analysis 단계까지 수행한 후, 산출물과 보고서를 RTC/Jazz에 등록한다. 위 결과에 정적 코드 분석 보고서가 차가된다.
  • deploy-jazz – 최종 단계인 deploy까지 수행한 후, 산출물과 보고서를 RTC/Jazz에 등록한다.

특별히 위와 같은 네 단계만 정의한 이유는 잠시 후 Build Definitions 절에서 확인할 수 있다. 그 전에 정적 코드 분석(static code analysis) 단계에서 무엇을 하는지 살짝 알아보고 가기로 하자.

Static Code Analysis

앞서 살펴본바와 같이, unit-test와 package 단계 사이에 code-analysis 라는 단계가 추가되었다. 이는 Maven에도 정의되어 있지 않은 단계이다. 이 단계에서는 제품의 소스 코드를 분석하여 잠재적인 결함과, 코딩 규약 준수 여부를 확인한다.

쉽게 활용할 수 있는 오픈 소스 툴들로는 FindBugs와 CheckStyle, PMD 등이 있다. (기능면에서 CodePro Analytix가 가장 마음에 드나, 아쉽게도 Ant용 task를 제공하지 않아 여기서는 제외하였다.)

FindBugs는 버그 패턴 위주로 거의 100% 적중률로 문제를 분석해주며, CheckStyle과 PMD는 그 외에도 코딩 규약, 유사 코드 검색 등 다양한 기능을 제공한다. CheckStyle과 PMD 는 기능면에서 상당히 겹치기 때무에 둘 다 사용할 필요는 없다. 나는 PMD를 더 선호하였지만, 최근에 업그레이드가 이루어지지 않고 있어 CheckStyle로 선회하였다.

참고로, 이들 툴을 지속적 통합 프로세스의 일부로 등록해놓는 것은 좋은 생각이긴 하지만 IDE에 통합하여 개발자들이 수시로 확인해보는 것에 비할 바가 못된다. 다행히 CodePro Analytix를 포함하여 위의 모든 툴들은 Eclipse 플러그인을 제공하고 있다.

관련하여 Java 코딩 규약 관리 방법 역시 참고가 될 것이다.

Build Definitions

빌드 정의(Build Definition)는 빌드에 필요한 각종 정보와 수행 조건 등을 담는다. 예를 들어, 빌드에 사용할 파일(build-jazz.xml)명, 타깃, 빌드 스케줄 등이 그것으로, 프로젝트 특성에 맞는 다양한 전략을 수립할 수 있다. 상세 내용은 본 글의 주제와 크게 관련 없으니  지나치도록 하겠다.

어쨌든 Jazz의 빌드 서버는 이 정의를 바탕으로 빌드 엔진에 빌드를 요청한다. 아래의 그림은 내가 구축하기 원하는 빌드 전략이다.

schedule

그리고 위의 전략을 구현하기 위해 다음과 같은 네 가지의 빌드 정의를 작성하였다.

  1. Continuous: 변경 사항에 대한 빠른 피드백을 목적으로, 컴파일/단위 테스트/패키징 성공 여부까지 확인한다.
    1. 빌드 주기: 매 5분
    2. 빌드 타깃: package-jazz
  2. Integration: 더 많은 시간이 소요되며 다양한 테스트를 수행하는 통합 테스트까지 수행한다.
    1. 빌드 주기: 매 1시간
    2. 빌드 타깃: integration-test-jazz
  3. Nightly: 일별 snapshot을 만들어, 매일 아침 baseline을 생성한다.
    1. 빌드 주기: 월~토요일 3:00 AM
    2. 빌드 타깃: code-analysis-jazz
  4. Weekly: 주간 변경 내용을 종합 검증하여 baseline을 생성하고, 개발 서버에 배포한다.
    1. 빌드 주기: 매주 일요일 3:00 AM
    2. 빌드 타깃: deploy-jazz

Jazz 빌드 서버는 위의 네 가지 빌드 정의에 기반해, 자동으로 빌드/테스트/배포를 수행하며, 그 결과를 개발자에게 알려주게 된다.

Summary

이상으로 빌드 시스템의 거시적인 구성부터 빌드 단계 정의, 빌드 정의를 통한 지속적 빌드 전략 수립까지 구성해 보았다.

다소 이론적인 면에 집중하여 설명하였지만, 상세 내용으로 들어가면 내용이 너무 길고 장황해지니 양해 바란다.

(관련 Ant 빌드 스크립트는 약간 다듬어서 추후 업데이트하겠음)

Java 코딩 규약 관리 방법
May 30th, 2011 by Wegra Lee

오랫만에 글을 적는 계기는, 얼마전 팀에 배포된 100페이지짜리 자바 코딩 가이드라인 때문이다.

나는 이미 약 9년 전에 나만의 코딩 가이드라인 문서를 만들어 다수 프로젝트에 적용했었다. 당시엔 나름 자부심을 주는 산출물 중 하나였지만, 얼마 지나지 않아 이것은 구시대적 산물이 되었음을 깨닫게 되었다.

코딩 규약 자체는 분명 필요하다. 이것이 없는 조직은 아직 굉장히 미숙한 개발 문화를 갖고 있을 확률이 높다. 문제는 이를 정적인 문서(워드나 파워포인트 형태)로 작성/관리한다는데 있다. 문서 방식의 대표적인 한계는 이러하다.

  • 내용이 풍부해질 수록 배우고 실무에 적용하기 어려워진다.
  • 언어 명세에 추가되는 새로운 문법에 빠르게 대응하지 못한다.
  • 항목 A의 예제 코드가 항목 B를 따르지 못하는 경우가 흔히 발생한다.
  • 몇몇 예제만으로 실 제품의 수십만/수백만 라인의 다양한 코드와 매칭시키게 하기에는 한계가 있다.

과거 시절에는 저런 한계를 안고서라도 문서가 필요했지만, 더이상은 아니다. 개발 도구들이 이미 충분히, 아니 비교할 수 없을 만큼 성숙되어 있기 때문이다.

Eclipse의 Code Formatter

가장 대표적인 자바 IDE 중 하나인 Eclipse를 보자. Eclipse의 Preferences > Java > Code Style 메뉴를 보면 다음의 메뉴들을 볼 수 있다.

  • Clean Up: 불필요한 코드나, 명백히 잘못된 코드 설정
  • Code Templates: 정형화된 코드 파일/클래스/메서드 등의 템플릿 설정
  • Formatter: 코드 포맷 설정
  • Organize Imports: import 문 구성 규칙 설정

위의 기능들은 개발 중 언제나 간단한 메뉴 조작이나 단축키로 바로바로 적용할 수 있다. 즉, 새로 합류한 팀원이 아무리 대충 짜놓은 코드라도, 즉시 베테랑 선임 개발자가 짠 코드처럼 바꿀 수 있다는 것이다. (기본 로직이나 단어 선택 등은 논외)

C/C++ 언어의 유사 툴을 사용해본 사람이라면 시큰둥할 수도 있다. 하지만 직접 저 메뉴들을 찾아들어가 잠시만 살펴본다면 그 막강한 표현력에 혀를 내두르고, 실제 프로젝트에 적용해보면 그 정확성에 감탄을 금치 못할 것이다.

더욱이 편집한 설정을 import/export 할 수 있으니, 기본 설정이 맘에 들지 않는다면 수정하여 팀 전체가 쉽게 공유할 수 있다. 소스 컨트롤 툴에 저장/관리한다면 금상첨화일 것이다.

하지만 코딩 규약은 단순 문법만 다루는 것은 아니다. 잠재적 결함을 예방하기 위한 올바른 코딩 패턴과 개발자들아 자수 실수하는 잘못된 패턴에 대한 예방 차원의 항목도 다수 포함된다. 위의 설정만으론 분명 부족함이 있다. 이에 대한 해결책으로는 두 가지 툴을 추천한다.

FindBugs

FindBugs라는 이름에서부터 너무도 명백하게 자신의 용도를 광고중인 이 툴은, 자바 코드에서 문제의 소지가 있는 다양한 버그 패턴을 찾고 그 이유를 설명해준다. 자신이 짠 코드에서 직접 짚어준다는 점에서 초간단 예제 몇 개만 달랑 던져주는 문서와는 천지차이다.

IDE와 통합은 기본이고 무료다. 또한 이 툴이 헛짚은 경우는 아직까지 겪어보지 못했을 정도의 정확성을 뽑낸다. 물론 ‘우리의 사용 환경에서는 절대 이런 일이 발생할 수 없어’라며 무시할 수는 있지만, 사용 환경이 언제까지건 변함 없고, 그 코드가 다른 프로젝트에 가져다 쓰일 확률이 zero 라고 확신하지 않는다면, 툴이 제안하는 예방 조치를 따라두는 것이 나쁠 것 없다.

CodePro Analytix

과거에는 PMDCheckStyle을 추천하며 CodePro Analytix는 소개 정도만 시켜주었는데, 이제는 상황이 바뀌었다. 구글이 이 툴을 사더니 무료로 뿌려버린 것이다. 더이상 상용 툴을 아쉬워하면 꿩 대신 닥으로 PMD나 CheckStyle을 사용할 필요가 없어졌다. 물론 이 둘을 무시하는 것은 아니지만, 개인적으로는 CodePro Analytix를 훨씬 높게 평가한다.

유사 코드 찾기종속성 분석 등 다른 기능도 많지만, 이번 주제와 밀접한 관련이 있는 기능은 바로 코드 검사 기능이다. CodePro Analytix는 Effective Java, Security, Internal API 등등 업계에서 많이 통용되고 있는 다수의 가이드라인에 맞는 수백가지의 검사 규칙을 제공한다. 각 규칙들은 세밀한 설정도 가능하고, 원하는 항목만 조합하여 팀만의 룰셋을 정의할 수도 있다. 이렇게 정한 규칙은 당연히 import/export 하여 공유할 수 있다.

Eclipse에 설치하려면 다음 주소를 참고하자.

http://code.google.com/intl/ko-KR/javadevtools/download-codepro.html

CheckStyle

CodePro Analytix로 천하통일할 수 있을 줄 알았으나, 확인 결과 CodePro는 Ant 태스크나 Maven 플러그인을 제공하지 않아, 지속적 통합 시스템에 넣기에 적합하지 않다. 하여 PMD와 CheckStyle 중 하나를 여전히 추천하지 않을 수 없는 상황이다. 둘 중 하나를 고르자면, 나는 CheckStyle을 추천한다. 이유는 간단하다. PMD가 2009년 이후 업데이트가 이뤄지지 않고 있는데 반해, CheckStyle은 지속적으로 업데이트 중이기 때문이다.

툴의 기능은 CodePro Analytix와 유사하나 지속적 통합 시스템에 바로 적용할 수 있도록 Ant 태스크와 Maven 플로그인을 제공한다. 물론 Eclipse와 같은 IDE용 플러그인 품질도 뛰어나 개발자 편의성도 좋다.

Summary

지금까지 살펴본 바와 같이, 자바 코딩 규약에 대해서는 이미 훌륭한 툴들이 갖추어져 있다. 문서로 힘들게 정리하고 교육하는 것보다는 이들을 활용하는 것이 백배는 효율적이다. 그 이유는 이들 툴 모두는 다음과 같은 장점을 제공한다.

  • IDE와 밀접히 통합되어 있어, 개발자들이 자신의 코드를 대상으로 언제든 쉽게 적용할 수 있다.
  • 무료이다.
  • 설정 편집 및 import/export 기능으로 팀원간 공유가 쉽다.
  • 강력하고 정확하다 (C/C++ 툴들과 비교를 거부한다).
  • Ant 태스크(FindBugs, CodePro) 혹은 명령행 수행 기능(Eclipse Code Formatter)을 제공하여 원한다면 지속적 빌드(continuous integration/build) 환경에 통합할 수 있다.

이 글을 읽는 사람이 자바 개발팀에 속해 있고 팀 내에 코딩 규약이 없거나 문서로만 관리되고 있다면, 지금이라도 늦지 않았으니 새로운 세상을 경험해보길 바란다.

새로운 툴을 대하는 자세
Sep 27th, 2010 by Wegra Lee

회사 생활을 하면서 나는 참 많은 툴들을 팀에 전파하려 노력하였고 또 전파한 편이다. 테스트 자동화, 분산 컴파일, 테스트 커버리지 측정, 프로파일링, 정적 코드 분석, 컨티뉴어스 빌드, 애플리케이션 라이프 사이클 관리 등 그 분야도 소프트웨어 개발 전반에 걸쳐있다.

매번 새로운 툴을 도입하려 할 때마다 사람들의 반응은 제각각이다. 툴이 제공하는 기능 리스트(무엇을 할 수 있다)만 보는 사람, 자신에게 당장 필요한 핵심 기능 몇 가지에만 관심을 갖는 사람, 이전에 사용해본 유사한 툴과 똑같은 취급하는 사람 등 많은 부류가 있다. 하지만 아쉬운 점은 정작 그 툴의 진정한 가치에 관심을 보이는 사람은 찾기 힘들다는 점이었다.

좋은 툴들엔 그 툴이 현재의 모습을 갖추기까지 거친 수많은 시행 착오로부터 얻어진 노하우와 설계자의 철학이 담겨 있다. 고객들로부터 받은 엄청난 양의 피드백 역시 툴의 기능과 동작 방식에 지대한 영향을 미친다.

툴을 제대로 익힌다는 것은 이러한 경험과 노하우를 함께 습득한다는 의미를 갖는다.

툴 제작자들은 고객이 별다른 교육 없이도 최대한 쉽게 사용하게 만들기 위해 많은 노력을 기울이지만, 여기엔 분명한 한계가 있다. 아무것도 없는 야구공 하나도 잘 던지라면 제대로 쥐는법부터 시작해 많은 학습과 연습이 필요하다. 하물며 복잡한 소프트웨어 개발을 위해 수많은 사람들이 함께 사용해야할 툴이라면 오죽하랴.

툴을 제대로 활용할 줄 모르는 사람에게는 어떤 툴을 제공하건 생산성에 큰 변화가 없다. 이들은 대부분 기본적인 기능만 사용하게 되는데, 기본 기능만 놓고 본다면 이름 있는 유사 툴들 사이에 큰 차이를 찾아보긴 어렵기 때문이다. 병목 현상이 발생하던 부분에서 성능이 대폭 개선되는 경우(분산 컴파일, 저장소 프락시 등)나, 개발자가 할 일을 대신해주는 경우(자동 빌드, 정적 코드 분석)와 같이 한정된 상황에서만 그나마 효과를 얻게 된다.

여기까지는 양호한 편이다. 심한 경우 툴이 만들어진 의도와 다르게 활용되는 경우도 많다. 툴의 설계자는 일반적인 사람들의 잘못된 습관을 바로잡기 위해 기능과 인터페이스를 설계했는데, 바로 그 잘못된 습관대로 일을 진행하면서 오히려 툴이 잘 맞지 않는다고 불만을 토로하기도 한다. 방법을 바꾸면 더 큰 효과를 얻을 수 있음에도, 왜 툴이 내 마음과 맞지 않는지는 깊게 생각하지 않는다.

이전보다 훨씬 다양하고 강력한 기능을 갖춘 툴을 보여줘도, 기존에 사용해본 유사 툴의 틀에 갖혀 장점을 보지 못하는 경우도 많다. ‘이 툴은 이런 거야’라고 일찌감치 단정짓고 더 이상 파고들려 하지 않는다.

이러한 태도를 버리지 못한다면 새로운 툴 도입이란 똑같은 일을 하기 위한 방법을 하나 더 익히는 것 이상도 이하도 아니게 된다. 결국 아무리 좋은 툴이 새로 나오더라도 도입에 보수적이게 되는 원인 중 하나가 된다.

팀원 전체가 그렇지는 못하다면, 개인적으로라도 툴에 녹아있는 사상을 공부하고, 제대로된 활용법을 익히려 노력해보자.

과거의 유사 툴이나 시장의 경쟁 툴들과 어떻게 다른지, 왜 다른지 파헤쳐보라. 같은 일이라도 다양한 접근법이 존재함을 배우고, 각각의 장단점을 깨달아 내가 처한 상황에서 최선의 방법을 찾을 수 있는 눈을 갖게 될 것이다.

내가 생각한 것과 다르게 동작한다면 왜 그렇게 만들었졌지 알아보라. 내가 하던 방식에서 많은 문제점을 발견하고 더 나은 방식을 배우는 계기가 될 것이다.

설계자가 그 툴을 만든 목적과 배경은 무엇인지, 어디에 주안점을 두었는지 알아보라. 내가 속한 팀, 나의 환경이 그들이 해결하고자 하던 문제를 그대로 앉고 있는가? 그렇다면 툴 도입이 해당 문제에 대한 확실한 해결책이 되도록 노력해보자. 문제를 인식/공유하고 툴 도입의 목적을 명확히 하자. 그리고 툴을 제대로 활용하고 있는지, 문제는 잘 개선되고 있는지 정기적으로 평가해보자.

툴 제작자가 권장하는 활용 방법(Best Practice)은 절대 빼먹어서는 안된다. 가이드라인을 잘 숙지하고 최대한 맞춰보려 노력해보자. 충분히 익숙해진다면 내가 생각하는 방식이 곧 툴이 동작하는 방식이 된다. 머리 따로 몸 따로 움직이던 시절을 떠올리며 여유 가득한 미소를 짓게될 것이다.

이러한 과정을 거치면서 툴 도입 효과가 극대화됨은 물론, 자신의 역량도 함께 성장한다. 제대로 활용할 줄 아는 툴이 많은 것은 좋은 개발자가 갖춰야할 덕목 중 하나이기도 하다.

IT 스터디.. 이렇게 진행해 보는 것은?
Jun 19th, 2010 by Wegra Lee

나는 작년에 마음에 맞는 사람 몇 명과 제법 참신하고 효과적인 스터디를 만들어 운영해보았다. 그 경험은 값진 기억이 되었고, 추후 여건이 다시 갖추어지면 유사한 형태로 재도전해보고 싶다. 여기 그 방식에 대해 간략히 소개해볼 터이니, 관심 있는 사람은 직접 주변인들과 시도해보길 권해본다.

내가 만들었던 스터디는 조금 특이했다.

가장 큰 특징은 참여자들이 준비해올 것이 없었다는 점. 스터디 자료로는 Google Tech Talk, iTunes U(niversity), Podcast, 인터넷상의 각종 기술 세미나, 최신 툴 데모 동영상, 유명인 인터뷰 동영상 등이었다. 세어보진 않았지만, 대략 백여 개의 흥미로운 자료들을 모을 수 있었다.

1시간 정도 동영상을 함께 보고, 30분 정도 토론한다. 부족한 정보는 그때그때 인터넷에서 검색해볼 수 있고, 더 깊은 지식을 원하거나 직접 해보고 싶은 것들은 action item으로 빼서 스터디 외 시간에 진행하기도 한다. 흥미로운 결과가 나오면 정리해서 스터디 팀 외의 사람들과도 공유했고, 실제 현업에 도움이 되는 일을 찾아 진행하기도 했다.

또한, 서로의 task plan(멤버 각자가 현업에서 실제 쓰는)을 리뷰하면서 planning 기술을 늘려가기도 하고, 코드 리뷰로부터 나온 유용한 패턴들을 공유하는 자리로도 활용했다.

별다른 준비 없이도 참여만 하면 지식과 지혜를 얻어갈 수 있는 모임이었고, 이런 특성이 스터디를 지속하는 데 큰 도움이 되었다고 믿는다.

매달 마지막 모임 때는 회고(retrospective)를 진행했다. 회고에서는 지난 한 달 동안 공부한 내용을 되짚어보고, 다음 한 달간 공부할 커리큘럼을 짠다. 스터디 진행 방식에 있어 개선이 필요한 부분을 논의해서 적용해본다. 주기적으로 동기를 부여하고, 부족한 부분을 지속 보강하여 모임의 생명력을 유지하고 발전시키는 수단이 되었다고 자평해본다.

이 모임은 매일 아침 7:30에 모여 9시까지 약 4달간 유지되었고, 일부 열성 멤버는 토요일에 모여 별도의 스터디(iPhone application programming)를 진행하기도 했다. 그러다가 내가 다른 목표가 생겨 탈퇴하면서, 아쉽게도 현재는 운영되지 않는 상태다.

운영하면서 어려웠던 점들도 정리해보았다.

- 참여자 대부분이 서로 다른 팀의 맴버였고, 같은 팀 안에서도 개개인이 독립적으로 일하는 문화 때문에 시너지를 일으키는 데 한계를 많이 느꼈다.

- 업무상 건물 간 이동이 잦은 멤버는 왔다갔다하는 불편을 겪기도 했다.

- 정식 업무가 아니라, 이른 아침 시간을 선택.. 참여하고 싶어도 나오지 못하는 사람도 있었다. 멀리 사는 사람, 아침잠 많은 사람 등. 소수 인원으로 운영하다 보니 두 명만 빠져도 스터디 진행에 영향을 미쳤다.

- 팀이 (반 강제적으로) 늦게 퇴근하는 문화로 바뀌면서 아침 스터디에 대한 부담이 점차 커졌다.

내가 이 스터디를 주창한 가장 큰 이유는 평소 동료 개발자들이 세상 돌아가는 정보에 너무 무관심하다고 느꼈기 때문이만, 진행하면 할수록 나 역시도 다른 멤버로부터 많은 정보와 깨우침을 얻게 된 값진 경험이었다.

[updated] 직접보기.. 혁신을 이끌어내는 방법
Feb 2nd, 2010 by Wegra Lee

쉬어가기.. 혁신을 이끌어내는 방법 [1]‘ 에서는 개발자들에게 쉬어갈 수 있는 시간을 제공함으로써 창의와 혁신을 이끌어는내는 이야기를 해보았다. 이번에는 ‘직접보기’라는 주제로 비슷한 이야기를 해보려 한다.

‘직접보기’ 가 필요한 이유는 아래의 그림을 보고 생각해보자. 이 그림이 말하고자 하는 원목적은 완전히 동일하진 않지만, 실물을 보지 않고 커뮤니케이션 했을 때의 문제를 효과적으로 말해주고 있다.

정리하면 고객이 원하는 것을 각 사람/조직마다 다르게 이해하고 있으며 심지어 고객 스스로도 자신이 무엇을 필요로 하는지 알지 못한다 것이다.

시장 조사를 토대로 고객의 needs 를 모두 만족시킨 제품의 출시 후 반응이 그리 좋지 않은 수많은 사례들을 잘 설명할 수 있는 논리이기도 하다.

혁신적인 제품을 잘 만들어내기로 유명한 애플(Apple)사의 경우, 신제품을 만들 때 시장 조사를 아얘 하지 않는 것으로도 유명하다(You Can’t Innovate Like Apple [2]). 시장에 존재하지 않는 제품에 대해 물어봐야 가치 있는 대답을 구하기 어렵기 때문이다. 대신 스스로 계속해서 실제품 수준의 프로토타입을 수없이 만들어보면서 직접 만져보고 써보며 자신들이 정말 이 제품을 원하는가를 판단한다. 그 결과 애플의 제품들은 종종 시장에서 당연히 필요하다고 생각하는 기능이 빠지기도 하고 이미 더 나은 제품들이 수두룩한데~ 라고 평가절하되곤 한다.

이미 만들어진 제품에 대해서는 다르다. 직접 사용해본 사용자들의 피드백은 소중하다. 애플 리테일 스토어가 중요한 역할을 수행하는데, 리테일 스토어의 직원들은 고객이 와서 들려준 이야기들을 놓치지 않고 본사로 보고하게 되어 있다. 그래서 스티브 잡스는 아이디어 도둑(유명 마케터 이해선 대표의 메시지 [3])이라는 말이 나오기까지 했다.

고객의 소리를 듣는 방식에 있어 두 경우가 다르다고 이야기했지만, 사실 그 원리는 동일하다. 바로 제품을 직접 만져보고 사용해본 사람들의 소리를 듣는다는 것이다.

이는 사실 애자일, 전통 할 것 없이 거의 모든 소프트웨어 개발 방법론에 중요하게 다루는 주제이고, 결론 또한 항시 동일하다. 짧은 반복 주기로 매 주기마다 동작 가능한 제품을 내놓고, 이를 고객에게 보여주고 피드백을 받는다. ‘당신이 말한 것을 우리는 이렇게 이해했는데, 이것이 정말 당신이 원했던 것이오?’ 를 확인하는 가장 중요한 절차인 것이다. 진정 공존을 원한다면 이 과정에서 쓸데없는 과장과 화려한 프리젠테이션은 없어져야 한다. 그리고 프로젝트 진행에 관련된 주요 인력들이 다 참석하는 것이 좋다. 고객, 프로젝트 리더, 영업 담당자, 주요 개발자들 등이 포함된다. 이들이 자주 모여 현실을 냉정하게 보고 허물없는 이야기를 하다보면 다음과 같은 반응들을 심심치 않게 목격할 수 있을 것이다.

  1. 내가 말했던 건 이게 아니었어요. 이러저런 모습을 상상했었는데요. 다음 릴리즈땐 이렇게 고쳐봐주세요.
  2. 내가 의도했던게 이게 맞긴 한데.. 직접 써보니 좀 이상하군요. 다른 아이디어가 있을까요?
  3. 이 부분은 제 생각과 다르긴 하지만.. 솔직히 지금이 더 좋아 보이는군요. 이대로 갑시다.

직접 보기는 서로의 생각을 확인하고 공유할 수 있는 가장 좋은 방법이며, 다음 방향을 결정짓기 위한 논의를 시작하기 위한 믿음직한 베이스가 되어준다.

또한 개발자들에게는 자신들의 창의력과 열정을 어필할 수 있는 절호의 기회가 되기도 한다. 직접 구현하면서 가장 먼저 써보게 되는 개발자들은 가장 빠르게 피드백을 줄 수 있는 훌륭한 고객인 셈이다. 이해한 요구사항대로 구현했을 시 불편한 부분이 있거나 더 나은 안이 떠오르면 릴리즈 전에 그 아이디어를 정리해두자. 가능하다면 직접 구현해서 보여주는 것이 가장 좋다. 직접 사용해본 고객과 말이나 문서 정도로만 본 고객은 확연히 다른 반응을 보인다.

이런식으로 개발자들의 능력을 인정받고 발언권을 강화해두는 것이 조직 전체의 커뮤니케이션과 생산성 향상, 제품 혁신에 긍정적인 영향을 줄 것이다. 개발자들은 기본적으로 창의적인 인력들이며, 이에 더해 현실적이다. Sci-fi 영화에나 나올 법한 허무 맹랑한 꿈을 꾸지도 않고, 일부러 과장하려는 경향도 적다. 먼 과거와 달리 골방의 괴짜들이 모여 있는 집단도 아니다. 윗사람들보다 신세대이며 소비의 주체라는 장점도 있다.

결론?

조직은 제품을 직접 보고 함께 이야기하는 문화를 정착시킴으로써 많은 것을 얻을 수 있다. 단, 어설프게 릴리즈 압박용으로만 오용하지 않도록 주의하자. 상향식 변화는 실패할 것이며, 하향식 변화는 성공한 것 처럼 보일 것이다. ^^ [4]

[updated]

사례를 몇 가지 추가해보기로 하였다.

  • Developing Torchlight [5] – Runic Games 사에서 Torchlight 라는 게임을 제작하는 방식을 이야기한다. 그들은 짧은 주기로 항시 play 가능한 게임을 만들어 개발자, QA 팀, 심지어 그드의 가족, 친구들까지 초대해서 게임을 즐기게 했다고 한다. 시장에서의 성공 여부는 아직 판가름하기 이르지만 기대를 가지고 지켜보고 있다.
  • 와우 성공 요인은? [6] – 초창기 와우 개발을 이끌었던 블리자드의 수석 PD 인 셰인 다비리 를 인터뷰한 내용이다. 초창기 가장 어려웠던 점 중 하나는 블라지드로써는 낯선 장르였던 MMORPG 의 비전을 경영진에 설득하는 것이었다고 한다. 직접 만들어 알파 버전을 보여주니, 절대 성공할 수 없다고 말하던 사람마저 하루 아침에 자신의 편이 되었다 한다.
  • Eclipse [7] 와 Jazz/RTC [8] – 오픈소스 개발 환경 프로젝트 중 역사상 가장 성공적인 프로젝트 중 하나인 Eclipse 와 그 개발 과정에서 얻은 노하우까지 툴에 녹이고 있는 Jazz/RTC 프로젝트도 좋은 예가 될 수 있다. 이들은 1년 주기의 정식 릴리스 사이에 6주 정도의 간격으로 다수의 안정적인 Milestone 버전을 내놓는다. 그리고 이전 릴리스 대비 어떤 기능이 개선되었는지 알기 쉽게 보여주는 New & Noteworthy 를 함께 알려주어서 사용자들이 정식 릴리스를 기다리지 않고도 새로운 기능들을 빠르게 접해볼 수 있다. Milestone 버전은 충분히 안정적이기 때문에 critical 한 프로젝트가 아니면 큰 부담 없이 새 milestone 을 테스트해본다. 이런 방식으로 사용자 커뮤니트의 빠른 피드백을 유도해 지속적으로 다음 릴리스에 반영해나간다.
  • Mobile SecondLife [9] – 내가 참여해 진행하다 중단된 프로젝트다. 과제 초창기부터 개발진에서는 도저히 성공 가능성이 없다고, 이걸 누가 쓰겠냐며 과제의 의미를 찾지 못하고 있었다. 링크의 데모는 연구 성격의 개념적 시연이어서 상당히 제한적인 환경에서만 동작 가능했다. 이를 바로 상품화하려 하니 현실적인 제약들 때문에 흥미로운 개념들의 거의 모두를 다 들어낼 수 밖에 없었다. 남은 것만으로는 정말 시도할 가치가 없는 과제였다. 하지만 그 목소리가 경영진에까지 전파되지는 못했다. 수개월간의 고생 끝에 만들어진 베타 버전을 임원에게 시연한 바로 다음날 과제는 바로 중단되었다.

References

  1. 쉬어가기.. 혁신을 이끌어내는 방법 (wegra.org)
  2. You Can’t Innovate Like Apple (Pragmatic Marketing)
  3. 유명 마케터 이해선 대표의 메시지 (제레미의 TV 2.0 이야기기)
  4. Bad Team Culture – 변화의 시작.. 상향식? 하향식? (wegra.org)
  5. Agile Approach in Game Development (wegra.org)
  6. 와우 성공 요인은? 전 수석 PD 셰인 다비리 인터뷰 (Inven Communications)
  7. Eclipse (Eclipse Foundation)
  8. Jazz/RTC (IBM Rational)
  9. Mobile SecondLife (Samsung)
설계 vs. 프로그래밍 언어
Dec 14th, 2009 by Wegra Lee
나는 객체지향 개념을 접하기 시작한 97년부터
모든 프로그램을 짤 때에 설계에 초점을 맞춰왔다.
그래서 자연스럽게
객체지향, UML, GRASP, Design Pattern, Bug Pattern, Refactoring, Aspect-Oriented 등등..
의 개념을 접하게 되었고,
실제로 3개월 정도 설계만 하고 보름 미만으로 코딩해서
제대로 돌아가는 프로그램을 만들어본 경험도 있다.
이리저리하여 난 설계의 중요성을 인식하고 권장하게 되었지만,
이상하게도 주위 다른 사람들은 그렇지 않았다.
처음엔 굉장히 답답하여 계몽(?) 시키고자 노력해보았지만,
설계를 시켜도 도저히 설계라 하기 민망한 수준에서 더 이상 진척이 없었던 것이다.
그러면서도 코딩을 시키면 마음엔 안들어도 그럭저럭 돌아가게는 만들어 냈다.
내게 ‘아하~!’하는 깨달음이 온 것은..
1년하고 조금 더 전쯤..
영어 공부 한답시고 한동안 자칭 ‘영어로 사고하기’ 놀이를 하고 다닌 적이 있다.
그러면서 깨달은 것은 ‘아는 만큼 생각한다’이다.
한국어로 생각하고 영어로 표현하려면 어휘력이나 문장력이 부족해 표현을 못한다.
하지만 처음부터 영어로 생각하면 사고의 범위 자체가 좁고 얕아지는 걸 느꼈다.
나는 남들에게 자신 있게
‘난 Java로 free talking 할 수 있다’고 얘기한다.
그리고 대다수의 배테랑 개발자들은
나와 같은 의미에서 자신의 주 언어로 free talking할 수 있을 것이다.
문제는 설계이다.
UML은 개발 언와와는 또 다른 종류의 언어이다.
하지만 거의 100%의 개발자들은 설계용 언어 보다는
개발용 언어를 먼저 익힌다.
필요에 의해서건, 흥미에 의해서건
설계용 언어를 접할 때는 이미 상당 수준의 개발 경험이 갖춰진 후이다.
그들에겐 낯설은 설계 언어로 사고하는 것은 너무 답답하다.
코드로 작성하면 금방 만들 수 있는 것도
설계 언어로는 어떻게 표현해야할 지 알질 못한다.
영어에 능숙치 못한 한국인이
미국인에게 무언가 얘기는 하고 싶은데
말 못하는 것과 마찬가지 이치다.
결국 설계를 하느니

그 시간에 직접 코딩하는 걸 택한다.

우연히 하드 디스크에서 발견한 글이다. 마지막 수정 시간은 2005년 4월 5일. 무슨 계기로 적어놨는지 기억도 나지  않고, 지금보니 설익은 느낌도 들지만 이곳으로 옮겨놓고 지워버리기로 했다. ^^

나는 객체지향 개념을 접하기 시작한 97년부터 모든 프로그램을 짤 때에 설계에 초점을 맞춰왔다. 그래서 자연스럽게 객체지향, UML, GRASP, Design Pattern, Bug Pattern, Refactoring, Aspect-Oriented 등의 개념을 접하게 되었고, 실제로 3개월 정도 설계만 하고 보름 미만으로 코딩해서 제대로 돌아가는 프로그램을 만들어본 경험도 있다.

이리저리하여 난 설계의 중요성을 인식하고 권장하게 되었지만, 이상하게도 주위 다른 사람들은 그렇지 않았다. 처음엔 굉장히 답답하여 계몽(?) 시키고자 노력해보았지만, 설계를 시켜도 도저히 설계라 하기 민망한 수준에서 더 이상 진척이 없었던 것이다. 그러면서도 코딩을 시키면 마음엔 안들어도 그럭저럭 돌아가게는 만들어 냈다.

내게 ‘아하~!’하는 깨달음이 온 것은.. 1년하고 조금 더 전쯤.. 영어 공부 한답시고 한동안 자칭 ‘영어로 사고하기’ 놀이를 하고 다닌 적이 있다. 그러면서 깨달은 것은 ‘아는 만큼 생각한다’이다. 한국어로 생각하고 영어로 표현하려면 어휘력이나 문장력이 부족해 표현을 못한다. 하지만 처음부터 영어로 생각하면 사고의 범위 자체가 좁고 얕아지는 걸 느꼈다.

나는 남들에게 자신 있게 ’난 Java로 free talking 할 수 있다’고 얘기한다. 그리고 대다수의 배테랑 개발자들은 나와 같은 의미에서 자신의 주 언어로 free talking할 수 있을 것이다.

문제는 설계이다. UML은 개발 언와와는 또 다른 종류의 언어이다. 하지만 거의 100%의 개발자들은 설계용 언어 보다는 개발용 언어를 먼저 익힌다. 필요에 의해서건, 흥미에 의해서건 설계용 언어를 접할 때는 이미 상당 수준의 개발 경험이 갖춰진 후이다.

그들에겐 낯설은 설계 언어로 사고하는 것은 너무 답답하다. 코드로 작성하면 금방 만들 수 있는 것도 설계 언어로는 어떻게 표현해야할 지 알질 못한다.

영어에 능숙치 못한 한국인이 미국인에게 무언가 얘기는 하고 싶은데 말 못하는 것과 마찬가지 이치다.

결국 설계를 하느니 그 시간에 직접 코딩하는 걸 택한다.

개발자 역량 평가 방식 비교
Nov 3rd, 2009 by Wegra Lee

개발자 역량을 평가하는 방식은 여러 가지가 있겠지만, 그 중 대조적인 두 가지의 방식에 대해 써볼까 한다.

해결 능력/팀 융화력 평가 vs. 지식 평가

마이크로소프트나 구글과 같은 회사는 면접 과정에서 난해한 문제를 내어 그 해결 과정을 직접 지켜보는 것으로 유명하다. 이들이 알아보고자 하는 것은 단순히 문제의 정답을 알고 있는가가 아니다. 주어진 상황을 정확히 이해하는가에서 시작하여 그 답을 찾기 위한 해결 과정 전반을 평가한다. 따라서 정답을 맞추지 못하더라도 높은 평가를 받고 합격되는 경우도 많다. 사람의 문제 응용/해결 능력은 시간이 지나도 쉽게 변하지 않는 특성이므로 이런 과정을 통해 뽑은 사람은 어떠한 일을 맡겨도 잘 해쳐나갈 가능성이 높다.

더불어 합격이 된다면 함께 일할 팀원들이 직접 면접에 참여하는 경우도 많다. 이는 그 팀에 잘 융화될 수 있는 사람인가를 팀원들이 직접 보고 판단하는 것이다. 좋은 팀들은 팀만의 문화가 있기 마련이다. 스포츠, 게임, 여행 등 취미를 공유한다거나, 특정 개발 방법론을 선호한다거나, 단순히 유머와 재치가 있는 사람을 원할 수도 있다.

이상과 대조적으로 지식을 평가하는 방식이 있다. 예를 들어 일부 기업은 주기적으로 전 사원들을 모아놓고 광범위한 지식을 평가하는 시험을 치른다. 몇 시간에 걸쳐 수십, 수백 개의 문제를 풀게 되는데, 대부분의 문제는 단순 지식 확인용이고, 응용 문제도 최대 몇 분 내에 답을 구할 수 있는 것들이다. 대학수학능력 시험과 유사하다고 보면 된다. 이 평가에서 높은 점수를 받은 사람은 다양한 분야에 걸쳐 폭넓은 기초 지식을 가지고 있다고 볼 수 있다.

지식 평가 방식의 맹점

지식 평가 방식도 일면 의미가 있으나, IT 업체에서 비중있게 활용하기에는 심각한 문제를 앉고 있다.

  • IT 분야는 인류 역사상 가장 빠르게 변화하는 분야중 하나이다. 즉, 특정 시점에 가지고 있는 지식은 그 유효 기간이 짧아, 좋은 평가를 받은 사람이 1년 후, 3년 후에도 같은 우월성을 보일 지는 장담하기 어렵다.
  • 지식이 많은 것과 실무에서의 문제 해결 능력 간의 연관성도 그리 크지 않다. 풍부한 어휘를 알고 있다고 해서 논리 정연한 글을 잘 작성하는 것은 아니며, 수학/과학 경시대회 참가자를 전과목 평균을 보고 선발하지는 않는다. 필기 점수가 좋은 사람과 텀 프로젝트를 잘 하는 사람은 다르며, 혼자서 잘하는 사람과 여럿이 함께 일하는 방법을 아는 사람은 다르다. 실무에서는 광범위한 지식보다는 전문화된 지식과 경험, 직관, 추진력, 커뮤니케이션 능력 등이 훨씬 더 유의미하다.
  • 현업에서는 수개월에서 심하면 수년간 특정 분야만 다루는 경향이 많으므로 력자일 수록 불리하다. 오히려 학업을 마치고 갓 입사한 사람이나 학계로 돌아가거나 이직을 준비중인 사람들이 높은 점수를 받기 유리하다. 평가만을 위해 현업과 관련 없는 지식들을 주기적으로 되세기게 하는 것은 기업 입장에서도 그리 현실적인 이득은 없다.
  • 지식은 필요하면 언제든 쉽게 찾을 수 있다. 지금이 어떤 세상인가?
  • 비용도 무시할 수 없다. 직원 1,000 명, 시험 시간 반나절인 상황을 단순 계산해보자. 한 사람을 1년간 고용하는데 1억 정도가 든다고 보면 (연봉, 보너스, 사무실 임대, 설비 유지, 복지 등 대기업 기준으로 현실적인 액수이다), 반 나절에 해당하는 비용은 20만원이 넘는다(1년중 working day 는 250일에 훨씬 못 미친다). 따라서 시험 1회당 2억원 이상의 비용을 소비한다는 결론이다. 문제 출제, 관리, 시험 전후로의 업무 집중도 하락, 기회 비용 등 정량적으로 계산하기 어려운 비용은 포함시키지도 않았다.

결론

지식 평가 방식이 절대적인 영향력을 미치는 경우는 아직 보지 못했다. 하지만 부분적으로나마 이런 평가를 수행하고 있다는 것 자체가 소프트웨어 개발 업무의 속성을 기업이 제대로 이해하지 못하고 있다는 반증이 아닐까.

한 번은 외국 개발자에게 국내 기업의 지식 평가 문화에 대한 짧은 견해를 들을 기회가 있었는데, 참으로 이해하기 힘들다는 반응이었다. 회사가 나를 뽑았다는 것은 나의 역량을 신뢰한다는 것이 아니냐는 말을 하였다. 나의 역량을 평가할 자격이 있는 사람은 나와 동고동락하며 함께 일하고 있는 동료들이지, 획일적인 시험의 결과만을 받아보는 사람들은 절대 아니다. 직작컨데, 어렸을 때부터 습득된 잘못된 교육 문화와 관료주의의 폐단인듯한 이 문화는 하루빨리 사라졌으면 한다.


References

  1. Programming Interviews Exposed – Secrets to Landing Your Next Job (번역서: 프로그래밍 면접 이렇게 준비한다)
»  Substance: WordPress   »  Style: Ahren Ahimsa