2014년 4월 24일 목요일

TDD 단상

어제밤 중에 TDD 이야기가 나온 김에 그냥 내 삽질 끝에 내린 생각 정리.

테스트를 먼저 작성
켄트 백의 책이 던진 충격 중에 가장 도발적이고 강력한 것이 이것이 아니었을까 생각한다.

"아직 아무 코드도 없는 상태에서, 실패할 테스트를 먼저 작성한다."

이것이 가지는 부수적인 효과는 다음과 같은 것들이라고 생각한다.

 1. 코딩에 들어가기 전, 어떤 인터페이스, 다시 말해서 어떤 인풋과 어떤 아웃풋을 가져야 할지를 먼저 생각하고 코딩에 들어가게 한다. 다시 말해서 내부 구현이 아니라 behavior에 의존하는 코드를 짜도록 강요한다.
 2. 매 다음 단계마다 테스트가 작성되므로 테스트가 각 '단위별'로 만들어지게 된다.
 3. 2의 여파로 각 단위가 고립되서 테스트되어야 하고 결과적으로 디커플링이 중요한 문제가 된다. 나는 mock을 이용하는 테스트가 멋지다고 생각한다.

이것들은 모두 좋은 디자인을 강제하는 방법으로 보였었다. 어떤 면에서는 전통적이라고 볼 수 있는 부분들도 있다. 나는 C를 A book on C, The C Programming Language 등으로 했었는데, 이 시절의 책들에서 실제 코드를 하기 전에 하도록 권유하는 것은 (테스트 작성은 아니고) 주석 작성이었다. 이것이 결국 인터페이스를 먼저 생각하라, 구현보다 인터페이스에 의존해라 등의 가르침이 아닌가? TDD는 이에 더불어 자동화된 테스트를 보유함으로써 리팩토링과 동전의 양면을 이룬다. 테스트될 수 있기 때문에 바꿀 수 있다.


나는 코드의 한 부분에서나마 이것들을 모두 지킬 강인한 의지가 있다면 충분히 경청할만한 방법이라고 생각한다. 그러나 당연히 만능이 아니다. 나는 그 한계를 내적인 것과 외적인 것으로 구분한다.


내적인 것은 TDD 자체가 가진 한계다. TDD는 함수, 프로시져, 메소드 단위에서는 좋은 디자인을 강요한다. 그러나 어떤 메소드가 어느 클래스에 속해야 하는지, 그 관계가 정확한 메타포를 형성하는지를 생각하도록 강제하지는 않는다. Car 클래스에서 drive()를 가져도 되는가? Driver클래스는 따로 만들어서 drive()는 Driver가 하는 것이 나을 것이다. 그러나 drive()의 테스트를 작성하는 순간, 그 사람은 drive()의 인풋과 아웃풋에 대해서 고민하겠지만 drive()가 Car에 속하지 않도록 강제하는 단계가 뚜렸하지는 않다고 본다.

외적인 것은 외부적인 상황 때문에 마주치는 한계이다. 대표적으로 GUI 프로그래밍의 경우 현재까지 사용자 인풋을 자동화하는 뾰족한 방법이 나왔다고는 보기 힘들다.  쓰레드 safety 문제도 TDD가 적절한 해법이 되기 힘들다고 보는데, 사실 이 외적인 한계들은 내적인 한계와 완전히 무관하지는 않다. 하나의 메소드가 synchronous 하게 인풋을 아웃풋으로 전환시키는 상황을 벗어나는 테스트는 본질이 아니기 때문이다.

이러한 "쓰면 되레 손해인 영역들"을 경험으로 확인해 나가고 쌓이는 것이 결국 TDD로 이득 보는 것을 가능하게 할 것 같다.

UEFI-GPT 부팅환경에서 페도라가 자동 생성하는 파티션

sda                                                                 
├─sda1 vfat                     8ABA-40EB                            /boot/efi
├─sda2 ext4                     cc7ef53e-c22c-438b-a070-3063822e020a /boot
├─sda3 swap                     3e8be53f-78c9-40b7-8f03-603a3b480fc8 [SWAP]
└─sda4 btrfs  fedora_isyru-e135 87837358-656a-4cb4-80d7-740e80af83a0 /

 
 Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048          411647   200.0 MiB   EF00  EFI System Partition
   2          411648         1435647   500.0 MiB   0700
   3         1435648         8808447   3.5 GiB     8200
   4         8808448       976773119   461.6 GiB   0700  


Arch, Gentoo같은 배포판 설치할 때 파티션을 어찌 설치해야 할지 모르는 상황에서 참고하기 위해서 씀.

2014년 4월 13일 일요일

emacs에서 git라면 역시 magit!!

emacs에서 git 사용은 당분간 magit로 쓰는 걸로 결정.

정확한 상황은 모르지만 emacs의 vc인터페이스가 기본적으로 git의

working directory - stage - commit

구조에 딱 들어맞지 않게 생겨 있는 게 아닌가 하는 생각이 들고, vc-git나 emacs-git나 이 문제에 있어서는 매한가지인 것으로 보임.

옵션 뒤지면 다 나올 수도 있겠으나, 뒤져야 나오는 건 그 자체로 문제.


그래서 당분간 magit를 쓰기로 했습니다. 우분투, 페도라 두 배포판 모두에서 제공됩니다.