학습을 목적으로 도메인 모델 기반의 마이크로서비스를 구현하였다.
개인 프로젝트에서 먼저 서비스 코드를 작성한 후, 테스트 코드를 추가하려다 보니 테스트를 우선 작성하는 테스트 주도 개발(TDD)과의 차이가 궁금해졌다.
또한, TDD와 함께 자주 언급되는 개념인 BDD, DDD와의 차이도 헷갈렸다. 이 글에서는 TDD, BDD, DDD가 소프트웨어 개발 생명 주기(SDLC)에서 어느 단계에서 등장하는 개념인지 정리하고, 이들 간의 차이점을 비교해보았다.
결론부터 말하자면, TDD와 BDD는 구현 단계에서 적용되는 개발 방법론이며, DDD는 요구사항 분석 및 설계 단계에서 등장하는 설계 원칙이다. 기존에는 이 세 가지가 모두 개발 단계에서 선택하는 방법론이라고 생각했으나, 실제로는 서로 다른 목적과 적용 시점을 가진 개념이었다.
특히, DDD를 "Domain-Driven Development"라고 소개하는 자료들도 많았지만, 정확한 표현은 "Domain-Driven Design(DDD)"이다. 단어의 뜻에서 알 수 있듯이, TDD(Test-Driven Development)는 개발 방법론(개발 프로세스)이고, DDD(Domain-Driven Design)는 도메인 중심의 설계 원칙이다.
그렇다면 SDLC 단계별 과정을 살펴보며 각각의 개념이 프로젝트에 어떤 영향을 미치는지 확인해보자.
소프트웨어 개발 생명 주기(SDLC, Software Development Life Cycle)는 소프트웨어 개발의 각 단계를 체계적으로 정의한 프로세스를 의미한다. SDLC를 적용하면 개발 프로세스를 명확하게 정의하고, 프로젝트의 품질과 효율성을 높일 수 있다.
SDLC는 일반적으로 다음과 같은 주요 단계로 나뉜다:
각 단계별로 적절한 개발 방법론을 적용하면 개발의 효율성과 안정성을 높일 수 있다.
요구 사항 분석은 시스템이 해결해야 할 문제와 기능을 명확하게 정의하는 단계이다.
이 단계에서 DDD 개념을 적용할 수 있다. 정확히는 요구사항 분석 단계부터 설계 단계까지 걸쳐 있다.
- DDD(Domain-Driven Design): 도메인 모델을 기반으로 복잡한 비즈니스 로직을 설계하는 접근 방식으로, 마이크로서비스 아키텍처에 적합
DDD에서는 핵심 도메인과 개념을 정의하고, 도메인 간의 관계를 정리하여 이후의 설계와 구현을 위한 기반을 마련한다. 이를 통해 마이크로서비스 아키텍처를 효과적으로 설계할 수 있다.
설계는 소프트웨어의 구조를 정의하고 개발 방향을 정하는 단계이다.
- 마이크로서비스 아키텍처(MSA) 설계: 각 서비스가 독립적으로 운영될 수 있도록 API, 데이터 저장소, 서비스 간 통신 방식 결정
- 테스트 전략 수립: 단위 테스트, 통합 테스트, 계약 테스트(Contract Testing) 등을 어떻게 적용할지 계획
DDD를 적용하여 도메인 모델을 정의하였다면, 이를 기반으로 마이크로서비스 아키텍처를 설계하기가 수월하다. 또한, 이 단계에서 테스트 전략을 수립하며, TDD와 BDD의 적용 여부도 논의할 수 있다.
구현 단계에서는 실제 코드를 작성하고 비즈니스 로직을 개발한다. 이 단계에서 TDD와 BDD를 적용할 수 있다.
- TDD (Test-Driven Development): 테스트 코드를 먼저 작성한 후 기능을 구현하는 방식
- BDD (Behavior-Driven Development): 기능이 동작하는 방식(행동)에 초점을 맞춰 TDD를 수행하는 방식
BDD는 TDD를 포함하는 개념으로, 테스트를 더 명확한 행동 기반 시나리오로 작성하는 접근법이다. 즉, 텍스트TDD는 "테스트를 먼저 작성하는 개발 방법"이고, BDD는 "테스트를 더 이해하기 쉽게 행동 기반 시나리오로 작성하는 방법"이라고 할 수 있다.
이 단계에서는 코드 작성뿐만 아니라 데이터 저장소와 인프라 구축 등 서비스와 관련된 모든 사항을 구현하게 된다.
테스트는 개발된 코드가 기대한 대로 동작하는지 검증하는 단계이다.
- 단위 테스트(Unit Test): 개별 컴포넌트의 동작을 검증하는 테스트 (JUnit, Mockito 활용)
- 통합 테스트(Integration Test): 여러 모듈이 올바르게 연동되는지 검증하는 테스트
- 계약 테스트(Contract Test): 마이크로서비스 간의 API 계약이 올바르게 유지되는지 검증하는 테스트 (Spring Cloud Contract, Pact 활용)
- End-to-End 테스트(E2E Test): 전체 시스템이 올바르게 동작하는지 검증하는 테스트
설계 단계에서 수립한 테스트 전략대로 검증을 진행하면 된다.
마지막으로 배포 및 운영은 개발된 소프트웨어를 실제 환경에 배포하고 운영하는 단계이다.
이 단계에서 CI/CD라는 개념이 등장하는데, CI/CD에서 테스트 코드를 검증하여 테스트 커버리지를 통과한 경우 통합 및 배포가 가능하도록 할 수 있다.
- CI/CD (Continuous Integration / Continuous Deployment): 자동화된 배포 파이프라인을 구축하여 빠른 배포 가능 (Jenkins, GitHub Actions, ArgoCD 활용)
이처럼 소프트웨어 개발에는 설계 단계부터 구현 및 테스트 단계까지 테스팅도 포함되어 이루어져 있음을 알 수 있다. TDD의 적용 여부는 선택이겠지만 테스트 코드의 작성은 의무적이라 할 수 있다.
테스트 코드의 작성이 의무적이라는 것은 테스트 코드를 우선 작성하는 TDD를 적용하는 것이 무조건 좋다는 것일까?
소프트웨어 개발에서는 제한된 자원(시간, 인력) 속에서 최대한의 효율을 내야 한다. 따라서 TDD가 항상 최선의 선택은 아닐 수 있다.
예를 들어, DDD를 적용하여 도메인 모델을 설계하고 마이크로서비스 구조로 설계를 했다면 단위 테스트보다 통합 테스트, 계약 테스트에 집중하는 것이 더 적절할 수 있다.
즉, TDD의 적용 여부보다 프로젝트 상황에 맞는 테스트 전략을 세우는 것이 더 중요하다.
이 글을 통해 헷갈렸던 개념인 TDD, BDD, DDD를 명확히 정리하고, TDD에 대한 강박을 내려놓을 수 있었다. 무조건적인 TDD 적용보다, 테스트 코드를 적극적으로 활용하면서 코드 품질을 높이고 테스트의 중복을 줄이는 것이 중요하다.
또한 앞으로 프로젝트 특성에 맞는 테스트 전략을 세우고, 효율적인 테스트를 수행하는 방향으로 개발을 진행하도록 노력해야겠다는 생각을 할 수 있었다.
참조
https://mynameiskgw.tistory.com/23
https://www.linkedin.com/pulse/tdd-vs-bdd-ddd-vitalii-serdiuk/
https://incheol-jung.gitbook.io/docs/q-and-a/architecture/ddd
https://jj-yi.tistory.com/51
https://www.youtube.com/watch?v=gs1qM1TF5zA