> For the complete documentation index, see [llms.txt](https://byulseop-til.gitbook.io/sinheeseop_til/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://byulseop-til.gitbook.io/sinheeseop_til/spring/101/spring_layered_architecture.md).

# SpringLayeredArchitecture

Spring 애플리케이션은 일반적으로 계층형 아키텍처로 구성됩니다. 이 문서에서는 각 계층의 역할과 효과적인 테스트 방법에 대해 알아봅니다.

## 1. 도메인(Domain)

* **엔티티 객체**
  * 예: `id`, `name`과 같이 실제 데이터베이스에 저장될 필드를 보유.
  * 애플리케이션의 핵심 비즈니스 데이터를 표현하며, 보통 **Getter/Setter** 또는 **Lombok**을 통해 필드를 접근.

## 2. 리포지토리(Repository)

* **인터페이스 기반 설계**
  * 예: `save()`, `findById()`, `findByName()`, `findAll()` 등과 같은 메서드를 추상화.
  * 추후 관계형 DB, NoSQL, 외부 API 등 다양한 저장소 구현체로 교체가 가능하도록 인터페이스로 설계하는 것이 핵심.
* **메모리 기반 구현체**
  * 실무 전환 전, 학습이나 빠른 프로토타입 용도로 간단히 **Map** 등을 사용해 데이터를 임시 저장.
  * 동시성 이슈는 고려하지 않았으며, **예제나 테스트 시** 편리하게 활용.

## 3. 테스트(Test)와 "Given-When-Then" 구조

### 테스트 구조

1. **셋업(Setup)**
   * 각 테스트(메서드) 실행 전, 필요한 객체나 데이터를 준비하는 단계.
   * JUnit에서 `@BeforeEach` 어노테이션을 사용하면 각 테스트마다 독립적인 초기화를 할 수 있음.
2. **클리어링(Clearing)**
   * 테스트가 끝난 후 환경을 원상태로 복구.
   * JUnit에서 `@AfterEach`를 통해 인메모리 저장소를 비우는 등 테스트 간 간섭을 방지.

### Given-When-Then (BDD 스타일)

* **Given(전제/상황)**
  * 테스트에 필요한 **입력 데이터나 상태** 준비.
* **When(행동)**
  * 테스트하고자 하는 **실제 동작**을 호출/실행.
* **Then(검증)**
  * 결과가 **예상대로** 나왔는지 확인(Assertion).

이러한 구조를 사용하면 테스트 시나리오가 명확해지고, **무엇을 테스트**하고 **어떤 결과**를 기대하는지 한눈에 파악하기 쉬워집니다.

## 4. 서비스(Service)와 DI(Dependency Injection)

* **서비스 계층**
  * 실제 비즈니스 로직이 위치하며, 필요 시 중복 검증이나 예외 처리 등의 핵심 로직을 담당.
  * 컨트롤러(또는 API)가 서비스 계층을 호출해 비즈니스를 수행.
* **의존성 주입(DI)**
  * 스프링에서는 보통 생성자를 통해 리포지토리 인터페이스를 주입(Constructor Injection).
  * 다른 구현체로 손쉽게 교체해도 서비스 코드는 수정 없이 재사용 가능.

## 정리

1. **도메인**: 핵심 데이터(엔티티) 구조를 정의.
2. **리포지토리**: 데이터 접근 계층. 인터페이스-구현체 구조로 설계해 유연성 확보.
3. **테스트**:
   * **Given-When-Then** 형태로 직관적인 시나리오 작성.
   * `@BeforeEach`와 `@AfterEach`를 통해 테스트 독립성 보장.
4. **서비스 & DI**:
   * 비즈니스 로직을 담당하는 서비스 계층.
   * 인터페이스 기반 리포지토리를 **생성자 주입** 받아 사용.

이러한 구조를 통해 **유연한 계층 분리**, **테스트 용이성**, **유지보수성**을 모두 확보할 수 있습니다. 특히 **Given-When-Then** 방식을 활용하면 테스트 시나리오가 명확해져, 예제 프로젝트뿐 아니라 실무 환경에서도 효과적인 검증 방식을 마련할 수 있습니다.
