강의

멘토링

로드맵

인프런 커뮤니티 질문&답변

광주_5반_김민우님의 프로필 이미지
광주_5반_김민우

작성한 질문수

Spring Boot TDD - 입문부터 실전까지 정확하게

실패하지 않은 테스트

아키텍처와 TDD의 오해에 대해 질문드립니다.

작성

·

34

·

수정됨

1

안녕하세요, 강사님! Spring Boot TDD 강의 정말 잘 듣고 있습니다. 강의 내용 중 궁금한 점이 생겨 질문드립니다.

보통 Spring에서 개발할 때 Controller-Service-Repository 구조의 레이어드 아키텍처를 많이 사용하는데요, 강의에서는 컨트롤러가 직접 리포지토리의 save 같은 메서드를 호출하면서 비즈니스 로직을 처리하는 경우가 있는 것 같습니다.

혹시 이것이 강의의 핵심 내용에 집중하기 위해 코드를 단순화하신 것인지, 아니면 강사님께서 실제로 선호하시는 개발 스타일이신지 궁금합니다. 만약 후자라면 어떤 장점이 있는지 그 이유에 대한 의견을 여쭙고 싶습니다.


더불어, "TDD를 잘하려면 인터페이스를 많이 사용해야 한다"는 것이 일종의 오해라는 말씀에 크게 공감했습니다. 그런데 왜 개발자들 사이에서 이런 오해가 생겨나게 된 것인지 그 배경이 궁금합니다.


마지막으로 추후에 비즈니스가 복잡해지면 테스트가 깨졌을 때 어디가 문제인지 파악이 어려울 것 같은데요 이에 따른 문제를 어떻게 해결하시나요? 단위테스트를 추가로 작성하시는지도 궁금합니다.

답변 2

1

이규원님의 프로필 이미지
이규원
지식공유자

민우님 안녕하세요. 강의 수강해 주셔서 고맙습니다. 질문에 답변 드리겠습니다. 🙂

레이어드 아키텍처 사용

저는 응용프로그램의 규모와 복잡도에 따라 아키텍처를 선택하는 편입니다. 그리고 테스트 대상 표면 내부의 설계에 대해서는 크게 신경쓰지 않습니다. 강의에서는 테스트 대상 표면으로 HTTP API를 사용했기 때문에 그 내부에서 어떤 아키텍처를 사용하는지는 그리 중요하지 않았습니다. 규모가 조금 큰 HTTP API 앱을 설계할 때는 컨트롤러와 그 외 부분을 분리해서 설계하긴합니다.

하지만 이 때도 '그 외 부분'의 내부에 대해서는 설계에 많인 비용을 들이지 않습니다. 특히 'Service' 접두어는 안티 패턴으로 규정하고 사용하지 않습니다. 'Service' 접두어를 사용하는 클래스는 덩치가 커지고 의존성이 복잡해지는 경향이 있기 때문입니다. 대신 '...CommandHandler', '...QueryHandler' 처럼 역할을 명확하게 규정한 작고 단순한 코드를 만듭니다.


'TDD를 잘하려면 인터페이스를 많이 사용해야 한다'는 주장의 배경

무비판적이고 기계적인 정보(DI, DIP, 헥사고날 아키텍처, ...) 수집의 병폐가 아닐까 싶습니다. 각 기법의 의미와 장단점을 이해하고 목적에 맞게 선별해서 사용하는 것이 아니라 어떤 이론에 나와있으니까 등의 이유로 특히 Java 생태계에서 많이 퍼진 것 같습니다.

그리고 Mockist 테스팅(지금은 안티 패턴으로 알려진)의 유행도 큰 영향을 미친 것 같습니다.

https://martinfowler.com/articles/mocksArentStubs.html#ClassicalAndMockistTesting


복잡한 비즈니스 논리 오류 추적

TDD를 하면 전체 코드는 복잡하더라도 모든 테스트를 통과하는 코드베이스에 조금씩 점진적으로 코드를 늘려갑니다. 그렇기 때문에 테스트가 실패하면 원인은 방금 만들어진 작은 변경 내에 있을 가능성이 높습니다. 그래서 문제를 찾는 것이 보통 어렵지 않습니다.

TDD를 하지 않는다면 상황이 조금 다를 수는 있지만, 그래도 테스트가 있는 상황이라면 문제를 쉽게 재현할 수 있고 디버깅 하기 쉽기 때문에 문제 원인 분석이 그렇게 어렵지는 않습니다.

그래서 저는 실패하는 테스트 때문에 테스트를 추가한 경험은 없는 것 같습니다.


답변이 부족했다면 말씀해 주세요!

0

안녕하세요, 인프런 AI 인턴입니다. 광주_5반_김민우님.

먼저, Spring에서의 아키텍처 구조에 대해 말씀드리겠습니다. 일반적으로 Controller-Service-Repository 구조가 많이 사용되는 이유는 각 레이어가 분리되어 있어서 각 역할에 맞는 책임을 지도록 설계되었기 때문입니다. 이러한 구조는 유연성과 유지보수성을 향상시키는데요, 이는 프로젝트가 커지고 복잡해질수록 더 중요해질 수 있습니다.

강의에서 컨트롤러가 직접 레포지토리에 접근하는 패턴을 본 경우, 이는 교육 목적 상 코드를 단순화 하고 본질적으로 이해하기 쉽게 하기 위한 선택일 가능성이 큽니다. 실제 프로젝트에서는 각 레이어가 명확히 분리되어 있으면 장기적인 유지보수에 더 유리할 수 있습니다.

다만, 간단한 애플리케이션이나 특정 요구사항에서는 이러한 레이어드 아키텍처의 모든 레이어를 꼭 따를 필요 없이 직접적인 접근이 오히려 간명하고 효율적일 수 있는 경우도 있습니다. 이는 프로젝트의 성격과 규모, 팀의 코딩 스타일에 따라 달라질 수 있습니다.

또한, “TDD를 잘하려면 인터페이스를 많이 사용해야 한다”는 오해에 대해 궁금해 하셨는데요, 이 오해는 주로 TDD 과정에서 테스트를 작성할 때, 테스트 대상을 격리시키기 위해 목(mock) 객체를 사용하는데 인터페이스가 유용하다는 점에서 비롯된 것 같습니다. 인터페이스는 객체 간 의존성을 느슨하게 유지하고, 목 객체로 대체하기 쉬운 환경을 제공하기 때문에 테스트 작성의 편의를 높일 수 있습니다.

하지만, 인터페이스를 남용하면 코드 복잡도가 증가할 수 있고, 과도한 추상화가 오히려 코드 이해를 어렵게 할 수 있습니다. 따라서 꼭 필요한 경우에만 사용하고, 프로젝트의 요구사항에 맞춰 유연하게 접근하는 것이 중요하다고 볼 수 있습니다.

질문자님의 이해를 돕기 위해 아래의 내용을 추천드립니다:

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

광주_5반_김민우님의 프로필 이미지
광주_5반_김민우

작성한 질문수

질문하기