tdd #소프트웨어검증 #과학적방법론 테스트주도개발 #인식론
핵심 요약
소프트웨어가 실제로 작동하는지 어떻게 알 수 있을까? 이 질문에 답하기 위해 마크 시만(Mark Seemann)은 철학의 인식론과 과학철학에서 비롯된 과학적 방법론을 소프트웨어 개발에 적용합니다. 과학자들이 가설을 세우고, 예측 가능한 실험을 통해 증거를 모으듯이, **테스트 주도 개발(TDD)**은 이 같은 과학적 검증 프로세스를 소프트웨어 개발에 체계적으로 구현한 방식입니다. 테스트를 먼저 실패시키고, 그 다음 통과시키는 이 과정을 통해서만 코드가 실제로 의도대로 작동하는지 경험적 증거를 수집할 수 있습니다.
상세 요약
1. 철학적 기초: 인식론과 과학적 방법론
1.1 과학에서의 진리에 대한 이해
- 절대적 확실성의 불가능성: 과학철학의 오랜 명제로, 우리는 어떤 것도 완전히 확실하게 알 수 없습니다
- 비점근적 접근(Asymptotic Approach): 실험과 관찰을 통해 진실에 점차 더 가까워질 수 있습니다
- 과학적 방법론의 핵심 구조:
- 가설 형성
- 예측 수립
- 실험 수행
- 예측 결과와 실험 결과 비교 (입증 또는 반박)
- 필요시 가설 조정
- 반복
1.2 갈릴레이 낙체 실험의 예
- 가설: 질량이 다른 두 물체를 같은 높이에서 동시에 떨어뜨리면 동시에 땅에 닿는다
- 실험 반복: 수천 번의 실험 (심지어 진공 상태에서도)이 수행됨
- 과학적 결론: 수천 번의 실험도 이것이 진실임을 증명하지는 못하지만, 매우 가능성 높게 만듭니다
2. 소프트웨어 개발에 적용된 경험적 인식론
2.1 제품 소유자의 관점
- 비기술 제품 소유자의 위치: 특정 문제를 해결하는 애플리케이션이 필요함
- 핵심 질문: 목표가 달성되었는지 어떻게 알 수 있는가?
- 과학자처럼 행동: 가설을 세우고, 예측하고, 실험(테스트)을 수행
2.2 테스트의 중요성
- 유일한 검증 방법: 테스트만이 소프트웨어가 실제로 작동하는지 판단할 수 있는 유일한 방식입니다
- 테스트의 다양한 형태:
- 임시적 vs 계획된 테스트
- 자동화된 vs 수동 테스트
- 철저한 vs 대충 한 테스트
- 각 테스트의 암묵적 가설: “이 단계들을 수행하면, 애플리케이션은 이 특정한 관찰 가능한 방식으로 행동할 것이다”
2.3 테스트 방식의 진화
-
과거: 전담 테스트 부서
- 테스트 관리자가 테스트 계획 문서 작성
- 수동 테스터들이 계획을 따라 실행
- 이것도 경험적 검증 방식이지만 문제점 존재
-
수동 테스트의 한계:
- 느린 속도
- 실수 발생 가능성
- 반복 수행 시 세부 사항 간과
-
자동화된 테스트의 필요성:
- 속도와 신뢰성 향상
- 새로운 문제 제기: “테스트 코드 자체도 버그를 포함할 수 있다면?”
3. 소프트웨어에서의 과학적 방법론 (Red-Green-Refactor 사이클)
3.1 첫 번째 단계: 테스트 먼저 작성 (RED)
시나리오: 프로덕션 코드 없이 자동화된 테스트만 작성
암묵적 가설과 예측:
- “이 테스트를 실행하면 실패할 것이다”
- 이것은 **반박 가능한 예측(Falsifiable Prediction)**입니다
예측 실패 분석 (기대와 다른 결과):
-
예측이 반박되는 경우 (테스트가 예상과 달리 성공):
- 테스트 코드가 잘못되었을 가능성
- 예: 동어반복적 단언(Tautological Assertion) 작성
- 근본 원인: 테스트 로직 결함
-
예측이 입증되는 경우 (테스트가 예상대로 실패):
- 과학적 성공: 가설을 반박하지 못함
- 테스트 코드가 올바르게 작성되었을 가능성 증가
3.2 두 번째 단계: 최소 코드 작성 (GREEN)
절차: 테스트를 통과할 만큼만 프로덕션 코드 작성
새로운 가설과 예측:
- “이 테스트를 실행하면 성공할 것이다”
- 역시 반박 가능한 예측
결과 분석:
-
예측 실패 (테스트가 예상과 달리 실패):
- 구현 코드의 결함 가능성
- 테스트 코드의 결함 가능성
- 심지어 우주선 입자 충돌도 가능(농담이지만 완전히 불가능하지는 않음)
- 문제의 원인 파악 필요
-
예측 입증 (테스트가 예상대로 성공):
- 가설을 반박하지 못함
- 코드가 의도대로 작동할 가능성 증가
3.3 세 번째 단계: 두 번째 테스트 추가 (RED)
새로운 테스트 작성:
- “모든 테스트를 실행하면, 새 테스트는 실패할 것이다”
- 반박 가능한 새로운 예측
순환 반복:
- 테스트 실패 (예측 입증): 테스트가 올바르게 작성되었을 가능성 증가
- 테스트 성공 (예측 반박): 테스트 로직 재검토
3.4 연속 구현: 모든 테스트 통과 (GREEN)
계속된 최소 코드 작성:
- “모든 테스트를 실행하면, 모두 통과할 것이다”
- 구현 코드 확장으로 새 테스트 통과 달성
과정의 누적 효과:
- 테스트 코드 정확성 증거 누적
- 프로덕션 코드 정확성 증거 누적
- 반증되지 않은 가설들의 축적
3.5 핵심 원리: 테스트 먼저 작성의 필수성
테스트 먼저 작성하지 않으면 잃게 되는 것:
- 첫 번째 실험 수행 불가능: 새 테스트가 실패할 것이라는 예측을 확인하지 못함
- 경험적 증거 수집 불가능: 테스트 코드가 올바른지 증명할 경험적 증거 없음
- 과학적 근거 상실: 전체 과학적 증거의 절반을 잃음
4. TDD가 과학적 방법론인 이유
4.1 명확한 정의
- **테스트 주도 개발(TDD)**은 과학적 방법론의 실제 구현입니다
- 새로운 테스트가 실패하는 것을 보는 것이 프로세스의 필수 부분
4.2 테스트 코드 읽기 vs 실행의 차이
단순히 테스트 코드 읽기의 한계:
- 과학적 입장: 고대 그리스 철학자들의 내성적 철학과 동등한 수준
- 고대 그리스의 오류된 이론: 네 가지 체액, 광학 이론(extramission), 원소설 등
- 결론: 코드를 읽으면 이해한다고 믿을 수 있지만, 실행 없이는 경험적 검증 불가능
실제 경험:
- 개발자들은 자신이 작성한 코드가 올바르다고 믿었으나 실제로는 오류 포함 경우가 많음
4.3 테스트 후 작성(테스트 마지막)의 문제점
테스트 통과 후 작성 시의 제한된 반박 가능성:
-
테스트 통과: 학습된 것이 거의 없음
- 테스트가 실제로 대상 코드를 검증하는지 불명확
- 동어반복적 단언을 작성했을 가능성
- 버그를 정확히 포착했을 가능성 (회귀 테스트로 기록됨)
- 실제 코드 경로를 커버하지 않을 수 있음
-
테스트 실패: 판단 불가능 상태
- 테스트가 잘못되었나?
- 프로덕션 코드가 결함이 있나?
- 확신 불가능
4.4 레거시 코드의 특성화 테스트(Characterization Test)
전통적 접근:
- “반드시 실패할 단언을 작성하라”
- (출처: Michael Feathers의 ‘Working Effectively with Legacy Code’)
권장 변형:
- 올바르다고 믿는 단언을 작성
- 테스트를 의도적으로 실패시키도록 시스템 조작
- 핵심: 테스트 실패를 반드시 확인
- 이유: 강력한 예측이 반박되지 않은 것이 중요한 경험적 증거
5. 결론: 소프트웨어 개발의 근본적 철학
5.1 핵심 질문의 답
“우리가 개발한 소프트웨어가 의도대로 작동한다는 것을 어떻게 알 수 있나?”
→ 답: 더 큰 질문 "우리는 어떻게 무언가를 알 수 있나?"로부터 나옵니다
5.2 과학적 사고의 해답
과학적 방법론 적용:
- 가설 수립: “소프트웨어가 주어진 조건에서 특정 방식으로 작동한다”
- 예측: 관찰 가능한 동작 예측
- 실험(테스트): 예측 검증
- 기록: 결과 기록
- 개선: 결함 수정
- 반복: 계속 과정 반복
5.3 TDD의 위상
- 매우 과학적인 방법론: 소프트웨어 개발 프로세스 중 가장 엄밀하고 효과적
- 도전적 현실: 과학도 어렵듯이 TDD도 어렵습니다
- 가치 제안: 소프트웨어가 의도대로 작동하기를 진정으로 원한다면, 가장 엄밀하고 효과적인 프로세스 중 하나입니다
실용적 팁과 주의사항
팁 1: 항상 테스트 먼저 작성하기
- 왜: 테스트가 실패하는 것을 보아야만 테스트 코드의 정확성을 경험적으로 증명할 수 있습니다
- 효과: 전체 과학적 증거의 절반을 상실하지 않기 위해 필수
팁 2: 테스트 실패 확인의 중요성
- 특성화 테스트 작성 시 테스트가 반드시 실패하도록 의도적 조작
- 이를 통해 테스트 로직이 실제로 작동함을 증명
팁 3: 코드 읽기와 실행의 차별성 인식
- 코드를 읽었다고 해서 이해한 것이 아님
- 반드시 실행하여 경험적 검증 수행
주의사항 1: 동어반복적 단언(Tautology) 회피
- 테스트가 무조건 통과하도록 작성되면 검증 불가능
- 테스트 작성 후 실패 여부 확인 필수
주의사항 2: 테스트 코드의 버그 가능성
- 테스트 코드도 프로덕션 코드 마찬가지로 버그 포함 가능
- 테스트 실패 원인 분석 시 테스트 코드도 검토 필요
주의사항 3: 레거시 코드 개선 시 주의
- 기존 버그를 실수로 정상 작동으로 기록하지 않도록 주의
- 테스트 작성 전에 실제 동작 확인 필수
참고 자료
-
기본 문헌:
- Mark Seemann의 2023년 컨퍼런스 기조연설 “Epistemology of software” (YouTube)
-
관련 저서:
- Michael Feathers, Working Effectively with Legacy Code, Prentice Hall, 2005
- 특성화 테스트(Characterization Test) 작성 기법 참조
- Michael Feathers, Working Effectively with Legacy Code, Prentice Hall, 2005
-
핵심 개념 링크: