본문 바로가기

Better SW Development

좋은 소프트웨어를 만드는 어떤 방식 하나, 테스트 주도 개발 (Test-Driven Development) : (상편)

소프트웨어를 만든다는건 공학(Engineering)인가, 예술(Art)인가?

이 두 의견의 충돌은 호사가들의 입을 통해 오랫동안 이어저 오는 논쟁꺼리에 해당한다.

이 논쟁에 '경제'개념까지 추가해서는 '산업'까지도 선택지 사이에 끼어들게 되면 '우리가 하는 일은 대체 어느 영역인가?'라는 혼란스러운 마음이 든다. 하지만, 이런저런걸 다 차치하고, 공학이 되었든 예술이 되었든, 아니면 장사가 되었든 공통적으로 추구하는 것이 하나 있다면, '제대로 동작해야 한다'는 목표다.


[아주 편리한 무료 계산기. 마이크로소프트 제품 아님!]

그런데 소프트웨어를 '제대로 동작하게 만든다'라는 말은 축구 감독이 선수들에게 '다른건 신경쓰지 말고 편하게 커다란 골대안에 공만 넣으면 돼! 기둥 맞추는건 어려우니까 왠만하면 시도하지 말고!'라는 주문 만큼이나 단순하지만 어려운 이야기다. '제대로 동작하는 소프트웨어를 만든다'라는 말에는 너무 많은 혼돈의 요소(Chaos Factor)들이 문장표현의 바깥 부분에 잠재되어 있기 때문이다.

솔직히 개발자들 중에서 자신이 만드는 소프트웨어를 잘 만들고 싶어하지 않은 사람이 있을까?  '난 시간도 무진장 들이고 돈도 잔득 써서 세상에서 제일 쓰레기 같은 소프트웨어를 만들거야!'라고 말하는 개발자는 없다. 다들 잘만들고 싶어한다. 잘하고 싶은데 안되는 것일 뿐이다.

왜?

소프트웨어라는게 이름만 소프트하고 실제로는 안 소프트 하니까...

즉... 잘 돌아가는 좋은 소프트웨어를 만든다는게 아.주. 어려우니까...


좋은 소프트웨어를 만드는 건 정말 어렵다. 모두가 원하지만, 거의 잘 안되는 영역중 하나다. 좋은 소프트웨어를 만들기 위해서는, 기본적으로 배워야 할 것이 너무 많다.

프로그래밍 언어부터 시작해서 각종 공학이론까지, 배워야 할 것도 많고, 해봐야 하는 것들도 많다. 사실, 이러저러한 것들을 한참 동안 배워도 배워도 어떻게 써먹어야 할지 막막할 때가 많다. 하다못해 넉넉한 시간과 경제적 여유가 있다면, 차분히 생각을 정리해 나가면서 조금씩 만들어 나갈텐데, 그런게 가능한 상업 프로젝트는 들어본 기억이 없다.

소프트웨어 개발 대부분의 경우에 있어,

취미로 만들면 취미로 만들기 때문에 위대한 소프트웨어가 되질 못하고, 자본과 사람이 많이 들어가면 소프트웨어 자체가 복잡해지는 바람에 또 위대한 소프트웨어가 되지 못한다. 그래 결국 대부분은 목표를 낮춰 낮춰서 그저 '잘 돌아가는 소프트웨어로만 만들자'라는 소박한(걸로 착각하는) 목표만 세우곤 하는데, 그건 착각에 착각이다.

수비고 공격이고 이젠 다 신경쓰지 말고,
상대편 골대안에 골만 넣어! 그냥 그렇게 하면 돼!

이런 느낌의 목표라는걸 잘 몰라라한다.
이 경우 대부분 한 두 골을 더 먹는게 일반적인 수순이다.



살짝 도메인을 벗어나서
좋은 자동차는 어떤 자동차를 말하는 걸까 생각해 보자.



우선, 잔고장 염려 없이 꾸준히 주행가능한 차가 좋은차의 1순위 중 하나일 것이다.
그리고 모양이 좋아야 한다.
그리고 운전자가 자동차를 편하게 이용할 수 있어야 한다.

모양이 좋아야 한다? = 디자인
편하게 이용할 수 있어야 한다? = 사용자 경험.
잔고장 염려 없이 주행가능한 차? = 좋은 설계가 바탕이 되는 탄탄한 내부구성

자동차가 가지는 최소한의 목적은 위 세 개중 마지막에 해당할 것이다.
그럼 마지막을 이루기 위해서 필요한 가장 기본 조건은 무엇일까?

아마, '신뢰도 높은 부품을 쓴다'가 가장 기본이 될 것이다.

나는 소프트웨어도 마찬가지라고 생각한다.
좋은 설계와 좋은 소프트웨어를 이루기 위해서는 좋은 부품(=모듈)이 밑 바탕에 자리잡고 있어야 한다.



다행히도, 이런 방식을 추구하는 개발 방식이 소프트웨어 개발 기법중에 존재한다.
나온지도 이제 십수년을 넘겼고, 뛰어난 개발자들은 기본으로 사용하고 있고,뛰어난 개발자가 되고 싶어하는 더 많은 수의 개발자들은 이 기법을 잘 사용하기 위해 노력하고 있다.

바로

'테스트 주도 개발(Test-driven Development, 이하 TDD)'이라고 불리는 개발 방식이다. 이 방식은 '단위 테스트 케이스'라는걸 먼저 만들어 놓고, 해당 테스트를 통과하는 코드를 작성하는 형태로 프로그램을 만들어 나간다. 코드를 작성하기 전에 테스트 케이스를 작성해 놓고, 이를 통해서 개발을 이끌어 나간다.

이렇듯, 테스트가 개발 단계별 진행을 주도적으로 이끌어 나가기 때문에, 테스트 주도 개발이라고 불린다.

이 방식은 모듈의 특성을 미리 정해놓고 개발하기 때문에, 목표로 하는 한계치와 경계값을 만족시키는 모듈이 작성과 함께 만들어지고, 변경이 가해지는 순간 순간이 만들어 놓은 테스트 케이스를 통해 점검 가능하게 된다. 그것도 아주 자연스럽게 말이다.

부끄러운 이야기지만,
난 회사내에서 분석설계 관련 과목과 디자인 패턴, 리팩터링등의 과목을 여러해 강의해 왔고, 요즘에는 애자일 기법을 사내에 전파하는 일을 한다.

그런데 수년 동안의 그 과정 안에서,

테스트주도개발이라는 기법은 아주 쉽게 시작해서 너무 많은 걸 얻을 수 있는 훌륭한 기법이라는 걸,
시간이 지날수록 점점 더 크게 느끼게 되었다.


(안타깝게도 많은 개발자들이 주로 글자로만 배우게 되는)상당수의 객체지향의 기본원리들이 TDD를 배우게 되면, 접근과 이해의 방식이 달라진다.

말하자면, 추상화, 응집도 증진과 커플링감소, 관심의 분리(SOC, Separation Of Concerns), 인터페이스에 의한 개발, 의존성격리 등등의 원리들이 그림과 글자로 배워서 말그대로 머릿속에 추상화되어 남는게 보통인데, TDD를 하면 개발도중에 자연스럽게 몸에 익혀진다.

왜? 테스트 케이스를 쉽게 만들려면 어쩔수 없이 코드의 모양이 객체지향 원칙을 추구하게 된다.

심지어 객체지향 원칙을 모른다 할지라도 말이다.

이를테면, 하나의 모듈이나 메소드가 많은 일을 하면 테스트 케이스를 만들기 어렵거나 복잡해 진다. 그럼, 자연스럽게 분리하려고 노력하게 된다. 또, 테스트 케이스는 한 번에 하나씩에 대해서만 만들도록 권장하는데, 그럴려면, 집중해야 하는 것이 무엇인지 관심영역이 어디인지 고민할 수 밖에 없다. 그리고, 모듈간의 커플링이 늘면 테스트 준비과정이 복잡해 진다. 없앨수 있는걸 찾거나 정 안되면 Mock을 들이민다. 처음엔 Mock의 신기함으로 시작하지만, 결국은 Mock 이 많아지면, 것도 힘들어진다는 걸 발견하면서 의존성이 주는 폐혜를 깨닫게 된다. 그 단계쯤 되면 '의존성을 가급적 줄여서 프로그램을 짜야겠다!'고 마음먹게 된다.

대충 예를 들었지만 이런식이다.

TDD 방식으로 개발하면 일반적인 경우보다 훨씬 간결하게 프로그램이 작성된다.

가끔 테스트 케이스 자체를 복잡하게 만들어서 TDD의 취지를 무색하게 하는 경우도 있지만, 그건 머리좋은 소수에 해당한다. 초반에 잘만 가이드 해주면 대부분은 잘 작성한다.

이제부터는 진짜 부끄러운 이야기에 해당한다.
(사실 쓰려니 손발이 조금 오그라...)

난 켄트 벡의 '테스트주도 개발(TDDBE)'책을 5번 샀다.

좋은 음악을 들으면 함께 듣고 싶은 마음처럼, 다 읽고는, 옆 사람에게 줬다.
그러다 시간이 지나 기억이 잘 안날때 쯤이면 다시 사서 읽었다.
그리고 또 관심보이는 옆 사람에게 주었다.

(후진 기억력이 크게 일조했지만) 그런식으로 해서 같은 책을 5번이나 사서 읽었다.

그런데, 어느날 충격을 받았다.

내가 책을 주었던 어느 누구도 TDD를 업무에 적용하지 않는 것이다.

왜??

이유를 물어봤다.

..
--- (하)편에서 계속.....

하편 : http://blog.doortts.com/124