항해 플러스를 진행하며 테스트 코드 주도 개발에 대해 접하게 되었다.
TDD를 적용하면 소프트웨어의 품질을 높이고 유지보수를 쉽게하며, 개발 속도를 향상 시키는 개발 방법론이라고 한다.
어쩌다 이런 방법론이 생겨났으며, 어떻게 이런 효과를 낼 수 있는 지 알아보도록 하자.
단어 그대로, 코드를 작성하기 전에 테스트를 먼저 작성하는 개발 방법론이다.
TDD의 기본흐름으로는 Red → Green → Refactor 과정을 반복하는 방식으로 진행된다.
Red(실패하는 테스트코드 작성) → Green(테스트를 통과하는 최소한의 코드 작성) → Refactor(코드 개선 및 최적화) 의 과정을 반복하면서 , 점진석으로 기능을 추가하고 코드의 품질을 개선해 나간다.
과거의 개발 방식은 요구사항 분석 → 설계 및 개발 → 완성 후 테스트 진행 → 배포 및 유지보수 의 순서로 진행 되었다.
이 방식은 개발이 끝난 후 테스트를 진행하므로, 심각한 결함을 발견하면 코드 수정이 어렵고, 기본 코드를 변경하면 어떤 기능이 깨질지 확신하기 어려우며, 일정이 부족하거나 압박에 의해 테스트가 생략될 수 있다는 치명적인 단점이 존재한다.
1990년대 후반, 켄트 벡은 "보다 신뢰할 수 있는 코드 작성 방법"을 고민하며
XP(eXtreme Programming)을 제안했고, 그중 하나로 TDD를 정립했다. TDD의 핵심 아이디어는 코드를 작성하기 전에 테스트를 먼저 작성하여 개발 과정에서 품질을 보장하는 것이다.
이 방법론은 이후 애자일(Agile) 개발과 함께 널리 퍼졌으며, 오늘날 대부분의 소프트웨어 엔지니어링에서 중요한 기법으로 자리 잡았다.
TDD에서는 먼저 테스트를 작성하는데, 이 과정에서 개발자는 내가 구현해야 하는 기능이 정확이 무엇인가?를 먼저 고민하게 된다 → 결과적으로, 명확한 목표를 설정할 수 있어 코드 품질이 향상된다.
TDD는 개발과정에서 코드 작성 → 테스트 실행 → 수정 이라는 주기를 반복한다.
이 과정에서 버그를 조기에 발견할 수있고 ,빠르게 수정이 가능하다
테스트 코드가 존재하면 기존 코드 수정 시, 기능이 정상적으로 동작하는지 빠르게 검증할 수 있다.
TDD를 따르면 결합도가 낮고, 재상용성이 높은 코드를 자연스럽게 작성하게 된다.
과거 개발 방식에서는 코드를 변경할 때 "이걸 바꾸면 다른 기능이 깨지지 않을까?" 하는 불안감이 컸다.
하지만 TDD를 적용하면 테스트가 보호망 역할을 해주기 때문에 안심하고 리팩토링이 가능하다.
TDD는 단순한 테스트 작성 방법론이 아니라, "안전한 개발 방식"을 제공하는 강력한 도구이다.
특히 애자일 개발, 지속적인 배포(CI/CD), 마이크로서비스 아키텍처와 같은 현대적인 개발 환경에서는 필수적인 기법으로 자리 잡았다.
이제 TDD를 왜 쓰는 지, TDD를 적용했을 때 어떤 점이 좋은 지에 대해 알아봤다.
그럼 이제 TDD는 어떤식으로 작성하는 지, 적용사례에 대해 알아보자
TDD는 "Red → Green → Refactor"의 세 단계를 반복하는 방식으로 진행된다.
Calculator 클래스에서 add(a, b) 메서드를 만든다고 가정을 해보자.
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
class CalculatorTest {
@Test
void testAddition() {
Calculator calculator = new Calculator();
int result = calculator.add(2, 3);
assertEquals(5, result);
}
}
add() 메서드를 찾을 수 없다는 메시지
class Calculator {
public int add(int a, int b) {
System.out.println(a + b);
return a + b;
}
}
테스트가 잘 동작되었음을 확인할 수 있다.
현재는 개선할 부분이 없지만, 만약 로깅 추가, 예외 처리 등을 하고 싶다면 여기서 진행할 수 있다.
기능을 개발하기 전에 오류 상황을 미리 고려하고, 실패하는 테스트 코드를 먼저 작성함으로써 잠재적인 버그를 조기에 발견하고 오류 발생 가능성을 낮출 수 있었다
만들어야 하는 기능과 예외 상황을 테스트 코드 형태로 정리할 수 있어 개발 과정에서 자연스럽게 체크리스트 역할을 수행한다.
코드를 변경하거나 리팩토링할 때, 테스트가 보호망 역할을 하기 때문에 기능이 정상적으로 유지되는지 즉시 확인할 수 있어 안정적인 코드 변경이 가능하다.
TDD는 강력한 개발 방법론이지만, 모든 상황에서 완벽한 해결책은 아니다.
기능을 개발하기 전에 테스트를 먼저 작성하고, 다양한 오류 케이스를 미리 예상하여 테스트를 작성해야 하므로, 초기 개발 시간이 증가할 수 있다.
기능이 변경될 때마다, 기존 테스트 코드도 수정해야 하므로 유지보수 부담이 커질 수 있다.
빠르게 개발해야 하는 프로젝트나, 변화가 잦은 기능은 TDD가 오히려 개발 속도를 저하시킬 수 있다.
지금까지 TDD의 장점과 특징에 대해 알아보았다. 하지만 TDD가 과연 효율적인가? 라는 질문에는 여전히 의견이 분분하다.
TDD에 관한 자료를 찾던 중 흥미로운 주장을 발견했다.
효율적인 테스트 코드 작성법 (포프)
소프트웨어 개발, 테스팅 또한 경제적인 활동이다.
자원(시간, 인력)을 적게 투입하여 최대한의 효용을 뽑아내어야 한다.
즉, 모든 코드에 테스트를 작성하는 것이 반드시 효율적인 것은 아니며,
테스트가 필요한 경우와 그렇지 않은 경우를 구분할 필요가 있다는 뜻이다.
1️⃣ 알고리즘이 매우 복잡하지만, 수학적으로 잘 정의된 경우
2️⃣ 제품이 실제로 사용되면서 코드가 자주 변경되는 경우
포프는 "모든 코드에 대해 먼저 테스트를 작성하는 TDD 방식을 사용하지 않는다"고 말한다.
그 대신, 일단 코드를 작성하고, 실제로 버그가 발생하거나 코드의 가정이 틀렸을 때 해당 부분에 대한 테스트 코드를 추가하는 방식을 선호한다.
이러한 접근법은 TDD의 단점(초기 개발 속도 저하, 유지보수 부담 증가)을 줄이면서도 실용적으로 테스트를 활용하는 방법이 될 수 있다.
코드 품질을 높이고, 안정적인 개발을 가능하게 하는 강력한 방법론이지만,
모든 프로젝트나 모든 코드에 적용하는 것이 항상 효율적인 것은 아니다.
따라서, 테스트의 필요성과 비용을 고려하여 전략적으로 TDD를 활용하는 것이 가장 현실적인 접근법이다.
퇴사 후, 개발자로서의 역량을 점검하고 성장하기 위해 저는 항해플러스 백엔드 과정을 수강하게 되었습니다.
이전 회사에서는 시니어 개발자가 부재한 환경에서, 주로 1~3년 차 개발자들끼리 운영되다 보니 성장에 대한 고민이 많았습니다. 하지만 항해플러스에서는 다양한 시니어 개발자분들의 멘토링을 받으며 인사이트를 얻고, 비슷한 연차의 개발자들과 교류하며 네트워크를 구축할 수 있었던 점이 큰 도움이 되었습니다.
물론 과정이 쉽지만은 않았고, 높은 성적으로 수료한 것도 아니었지만, 그 과정에서 배운 것들은 분명히 의미가 있었습니다.
저는 이를 실패한 경험이 아니라, 오히려 개발자로서의 성장 방향을 점검하는 값진 기회라고 생각합니다.
저와 비슷한 고민을 하고 계시거나, 성장에 대한 방향성을 찾고 있는 분이라면 한 번 경험해보시길 추천드립니다.
현재 항해플러스 새로운 기수 모집 중입니다. (~3/18 11:00까지)
지원 시, 추천인 코드를 입력하면 20만원 할인 혜택을 받을 수 있으니 참고 부탁드립니다.
추천인 코드 : HYPmjJ