최근 아키텍처와 테스트의 관계에 대해 깊이 고민하게 되었다. 특히 "테스트하기 쉬운 코드가 곧 잘 짜여진 아키텍처"라는 말이 계속 머릿속을 맴돌았다. 이를 통해 깨달은 점들을 정리해보려 한다.아키텍처란 무엇인가?아키텍처는 단순한 설계 도구가 아니다. 비즈니스 문제를 해결하기 위해 준수해야 하는 제약을 넣는 과정이라고 생각한다. 이는 테스트 코드가 일종의 규약으로 작용한다는 점과 맥을 같이 한다. 중요한 건 아키텍처를 도입할 때는 반드시 그 이유에 대한 구성원들의 공감이 필요하다는 점이다. 공감 없는 아키텍처는 그저 장애물일 뿐이니까.아키텍트의 진정한 목적아키텍처를 다루는 아키텍트의 주요 목적은 결국 인적 자원의 절감이다. 이를 위해서는 다음과 같은 요소들이 필수적이다:동시 작업이 가능한 구조명확한 관심사..
@Builder 어노테이션은 내가 가장 애용하는 도구 중 하나다. 객체 생성 시 높은 유연성을 제공하며, Spring을 사용할 때 자주 활용했다. 하지만 이러한 의존성이 때로는 과도했음을 돌아보게 되었다.@Builder의 유연성@Builder의 가장 큰 장점은 객체 생성의 유연함이다. 모든 매개변수를 한꺼번에 전달할 필요 없이, 가독성 있고 깔끔하게 객체를 생성할 수 있다. 이는 특히 복잡한 객체나 선택적 필드를 가진 객체를 생성할 때 매우 유용하다. 하지만 강력한 도구일수록 신중하게 사용해야 한다.Entity 클래스에서 @Builder의 문제점특히 DDD(Domain-Driven Design) 관점에서, 엔티티는 무결성과 캡슐화를 엄격히 준수해야 한다. @Builder가 제공하는 유연성은 이러한 원칙을..
소프트웨어 개발에서 "의존성"은 피할 수 없는 개념이다. 의존성을 적절히 관리하지 않으면 코드가 복잡해지고, 유지보수와 테스트가 어려워진다. 이번 포스팅에서는 의존성, 의존성 주입(DI), 의존성 역전(DIP) 개념과 이들이 테스트 가능성과 어떤 연관이 있는지 정리해보려고 한다.의존성이란?컴퓨터공학에서 말하는 의존성은 결합과 같은 개념으로, 한 객체가 다른 객체의 동작이나 데이터를 필요로 하는 관계를 의미한다.A가 B를 사용하면 A는 B에 의존한다.예: A 객체가 B 객체의 메서드를 호출하거나 데이터를 참조하면, A는 B에 의존성을 가진다.의존성은 소프트웨어에서 자연스럽게 발생하지만, 이 의존성이 과도하거나 명확히 드러나지 않으면 설계와 유지보수에 문제가 생길 수 있다.의존성 주입(DI, Dependen..
소프트웨어 개발에서 테스트는 단순한 "코드 검증" 이상의 역할을 한다. 특히, TDD(Test-Driven Development)와 BDD(Behaviour-Driven Development)는 테스트를 통해 설계와 개발 방향성을 잡아가는 접근법이다. 이번 포스팅에서는 TDD와 BDD를 중심으로, 테스트와 관련된 다양한 개념들을 정리해보려고 한다.SUT란?테스트하려는 대상을 SUT(System Under Test)라고 부른다.즉, 테스트의 주요 대상이 되는 시스템, 메서드, 혹은 클래스를 지칭하는 용어다.SUT를 잘 정의하는 것은 테스트의 초점을 명확히 하는 데 중요하다.BDD (Behaviour-Driven Development)BDD란?BDD는 TDD에 "행동(Behaviour)"을 강조한 방식이다...
TDD를 하면서 많은 사람들이 빠지는 함정이 있다. 바로 "테스트 커버리지에 집착하는 것"이다. 테스트는 어디까지, 어떻게 작성해야 할까? 그리고 모든 메서드를 테스트해야 할까? 이런 질문에 답을 찾기 위해 이번 포스팅에서는 TDD의 핵심과 테스트 코드 작성의 방향성을 정리해보려고 한다.너무나 명확한 코드는 테스트하지 말자모든 코드를 테스트하려는 강박은 때로는 비효율적이다. 특히, 너무 단순하거나 명확한 코드라면 테스트를 작성하지 않아도 될 수 있다. 예를 들어, 단순한 getter/setter, 혹은 너무 기본적인 로직은 테스트 작성 없이도 충분히 신뢰할 수 있다.테스트 작성에서 피해야 할 것무의미한 테스트단순히 "테스트 코드 커버리지를 높이겠다"는 목적만으로 작성된 테스트는 아무런 가치를 주지 못한다..
@Vaild 어노테이션으로 유효성 검사를 하기 위해 다음과 같은 HTML 코드를 작성했다. Incorrect data Incorrect data 그리고 해당 뷰를 렌더링 하기 위해 다음과 같은 컨트롤러를 작성했다. @GetMapping("/articles/post") public String showArticleForm(Model model) { return "contents/community/community-write"; } 하지만 렌터링이 되지 않는 에러가 발생했고, th:object 를 사용하려면 dto를 model에 담아줘야 한다는 사실을 알게됐다. @GetMapping("/articles/post") public String showArticleForm(Model model) { model.a..
@Slf4j @RequiredArgsConstructor @RestController @RequestMapping("/api/my") public class MemberApiController { private final MemberService memberService; @PatchMapping("/hospital") @ResponseStatus(HttpStatus.OK) public String appendFavorites( @AuthenticationPrincipal UserDetails principal, @RequestParam("hospitalSeq") Long hospitalSeq ) { log.info("=========================={}====================..
@Transactional(readOnly = true) public List findReviewsByMemberEmail(String memberEmail) { List reviews = reviewRepository.findReviewsByMemberEmail(memberEmail); return reviews.stream() .map(ResponseReviewDto::toDto) .sorted(Comparator.comparing(ResponseReviewDto::getReviewSeq) .reversed()) .collect(Collectors.toList()); } 다음과 같이 수정하면 된다. 여기서 .map(ResponseReviewDto::toDto) 까지는 자주 사용하는 람다식이지만 그 밑..
문제의 컨트롤러 @PostMapping("/post") // redirect 시 ResponseStatus 어노테이션을 붙이면 redirect가 실행되지 않습니다. // @ResponseStatus(HttpStatus.CREATED) public String createReview( @Valid RequestReviewFormDto requestReviewFormDto ) { reviewService.createReview(requestReviewFormDto); return "redirect:/my/reviews"; } @ResponseStatus를 이용해 상태코드를 같이 전송할시 redirect가 실행되지 않는 오류를 겪었다. 이유는 ResponseStatus는 Body에 상태값을 실어서 보내지만 타..
Spring Data JPA에서 JpaRepository를 extends 해줄때 선언해준 객체를 준수하지 않고 Integer 타입을 반환하려고 했을때 해당 오류가 발생했다. 문제의 코드 package com.playdata.eungae.appointment.repository; import java.util.List; import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa...