diff --git a/keyword/chapter04/keyword.md b/keyword/chapter04/keyword.md new file mode 100644 index 0000000..73f343e --- /dev/null +++ b/keyword/chapter04/keyword.md @@ -0,0 +1,209 @@ +### 아키텍처 구조 + +프로젝트의 뼈대를 어떻게 구성할지 미리 설계하는 것 + +**아키텍처 구조를 설계하는 목적** + +- 유지보수의 용이성 + - 목적에 따라 코드 분리를 해놓기 때문에 나중에 기능 추가할 때 큰 수정 필요 없음 + - 정형화된 구조를 사용한다면 타인이 알아보기가 쉬워져서 타인과 협업, 유지보수하기 좋아짐 + +→ 따라서 다른 사람이 쉽게 이해하고 불필요한 의사소통을 최소화할 수 있는 구조를 짜는게 중요! + +**아키텍처 구조의 종류** + +- 계층 기반 구조 : 시스템 계층(controller, service 등)을 기준으로 파일을 분류 하는 것 + + + - 장점 + - 프로젝트를 패키지 구조만 보고 전체적인 구조를 파악할 수 있다 + - 애플리케이션의 API를 보고 흐름을 파악하고 싶다면 Controller 패키지 하나만 보고 파악할 수 있다 + - 애플리케이션의 비즈니스 로직을 보고 싶다면 Service 패키지 하나만 보고 파악할 수 있다 + - 계층별 응집도가 높아진다 + - 계층별 수정이 일어날 때, 하나의 패키지만 보면 된다 + - 각 계층별 독립적인 테스트 가능 + - 단점 + - 도메인 별 응집도가 낮다 + - user 도메인의 흐름을 보고 싶을 때 모든 패키지를 봐야함 + - 한 도메인의 기능 변경 시 변경 범위가 크다 + - 유스케이스 별로 쪼개는 것이 어려워진다 + - 한 클래스 안에 다 넣자니 코드가 너무 길어져서 읽기 힘들어지고 + - 한 패키지 안에 유스케이스 별로 다 쪼개서 넣으면 패키지 속에 클래스가 너무 많아서 파일 찾기가 힘듦 + - 규모가 커지면 하나의 패키지 안에 여러 클래스가 있어서 구분이 어려워진다 +- 도메인 기반 구조 : 도메인을 기준으로 파일을 분류하는 것 + + + - 장점 + - 도메인 별 응집도가 높아짐 + - 한 도메인의 흐름을 보고 싶을 때 하나의 패키지만 보면 됨! + - 도메인 기능 변경 시 변경 범위가 작아짐! + - 유스케이스 별 세분화해서 표현 가능 + - 단점 + - 애플리케이션의 전체적인 흐름 파악하기 어렵 + - 개발자의 관점에 따라 어느 패키지에 둘지 애매한 클래스 존재 + - 도메인 간 협력 어려움 + +**→ 따라서 단순하게 보자면 규모가 작고 도메인이 적다면 아키텍처, 규모가 크고 도메인이 많다면 도메인형으로 선택하자!** + +### Swagger + +api를 구현하면 그에 맞춰서 자동으로 문서화 해주는 도구 + +- 장점 + - 일일히 작성하지 않고 개발만 끝나면 자동으로 바로 작성 + - 화면에서 직접 API 테스트가 가능 + - postman 같은 별도의 앱 없이 웹에서 바로 파라미터를 입력하고 api 호출해보기가 가능! +- 단점 + - 개발 끝나기 전까지 프론트가 현황을 확인 불가 + +**자주 사용하는 어노테이션** + +- @Tag: API 그룹 짓기 + - 비슷한 API들을 묶어서 제목과 설명을 달아줌 + - 사용처 예시 : controller 클래스 위 +- @Operation: API 기능 설명 + - 한 API가 구체적으로 어떤 기능을 하는지 설명 +- @ApiResponse: 상태 코드별 응답 설명 + - 성공하면 200번, 실패하면 404번 같은 상태 코드를 미리 설명 +- @Parameter: 요청 변수 설명 + - @PathVariable이나 @RequestParam이 어떤 의미인지, 예시 값은 무엇인지 적어줍니다 +- @Schema: DTO 필드 설명 + - 요청으로 어떤 값을 받을지, 응답으로 어떤 값이 나갈지를 설명 + +```java +@Tag(name = "학식 메뉴 API", description = "기숙사 및 학생식당 메뉴 관련 API입니다.") +@RestController +@RequestMapping("/api/menus") +public class MenuController { + + @Operation(summary = "오늘의 메뉴 조회", description = "특정 식당의 오늘의 메뉴 목록을 가져옵니다.") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "메뉴 조회 성공"), + @ApiResponse(responseCode = "404", description = "해당 식당을 찾을 수 없음") + }) + @GetMapping("/{restaurantId}") + public List getTodayMenu( + @Parameter(description = "식당 ID (예: 1-학생회관, 2-기숙사)", example = "2") + @PathVariable Long restaurantId) { + + // ... 메뉴 조회 로직 ... + return menuList; + } +} +``` + +```java +@Getter +public class MenuResponseDto { + + @Schema(description = "메뉴 이름", example = "치즈돈까스") + private String menuName; + + @Schema(description = "메뉴 가격", example = "5500") + private int price; + + @Schema(description = "품절 여부", example = "false") + private boolean isSoldOut; +} +``` + +### 도메인형 아키텍처 + +도메인을 기준으로 파일을 분류하는 것 + + +- 장점 + - 도메인 별 응집도가 높아짐 + - 한 도메인의 흐름을 보고 싶을 때 하나의 패키지만 보면 됨! + - 도메인 기능 변경 시 변경 범위가 작아짐! + - 유스케이스 별 세분화해서 표현 가능 +- 단점 + - 애플리케이션의 전체적인 흐름 파악하기 어렵 + - 개발자의 관점에 따라 어느 패키지에 둘지 애매한 클래스 존재 + - 도메인 간 협력 어려움 + +프로젝트 전반적으로 사용되는 config, auth, error 같은 클래스들은 domain과 같은 레벨에서 global이라는 패키징 안에 구성한다 + +### DDD vs 도메인형 아키텍처 +- 도메인형 아키텍처는 패키지의 구조를 설계하는 방식이고 DDD(도메인 주도 설계)는 그것보다 더 거대한 개념으로 소프트웨어 시스템을 설계하고 개발하는 것에 대한 방법론이다 + +### DDD (Domain-Driven Design, 도메인 주도 설계) + +도메인 모델을 기반으로 복잡한 소프트웨어 시스템을 설계하고 개발 +여기서 도메인이란 비즈니스 문제 영역을 말한다 메뉴 도메인, 리뷰 도메인 같이 큰 문제 공간을 예시로 들 수 있다 + +- **이를 통해 각각 도메인을 철저히 분리하여 높은 응집력과 낮은 결합도로 변경과 확장에 용이하다!** + +**DDD 핵심 개념** + +- 도메인 모델 : 도메인 전문가와 개발자가 공유하는 비즈니스 지식을 소프트웨어로 표현한 핵심 모델입니다 + - 엔티티 + - 고유 식별자(ID)를 가진 객체입니다 + - 데이터가 변해도 식별자를 통해 동일한 객체로 계속 추적할 수 있습니다 (예: 사용자, 미션, 가게) + - 밸류 오브젝트 (Value Object) + - 고유 식별자가 없고 값 자체가 중요한 불변 객체입니다 + - 값이 같으면 완전히 동일한 객체로 취급하며, 변경 시 통째로 교체합니다 (예: 주소, 금액, 날짜) + - 애그리게이트 (Aggregate) & 애그리게이트 루트 (Aggregate Root) + - 애그리게이트**:** 데이터 일관성을 유지하기 위해 관련된 엔티티와 밸류 오브젝트를 한 덩어리트랜잭션 단위로 묶은 집합입니다 + - 애그리게이트 루트: 이 덩어리를 대표하는 대장 엔티티입니다. 외부에서는 무조건 루트를 통해서만 내부 데이터를 변경할 수 있도록 철저히 통제합니다 + - 리포지토리 + - 도메인 객체를 DB 같은 영구 저장소에 저장하고 조회하는 인터페이스입니다 + - DDD에서 리포지토리는 모든 엔티티마다 만드는 것이 아니라, 오직 애그리게이트 루트 단위로만 생성합니다. +- 애플리케이션 서비스 (Application Service) + - 정의: 사용자의 요청을 받아 도메인 객체들을 조종하는 흐름 제어자 + - 특징: 서비스 클래스 안에 복잡한 계산이나 비즈니스 규칙을 직접 적지 않습니다. DB에서 엔티티를 꺼내고, 엔티티에게 로직을 실행하라고 명령한 뒤, 그 결과를 다시 DB에 저장하는 역할만 담당합니다. + +**계층 구조** + + +- Presentation Layer + - controller에 해당 + - 사용자의 요청을 받고 응답을 반환하는 api 정의 +- Application Layer + - service에 해당 + - 하지만 기존 아키텍처 구조에서의 service하고는 다름 + - 절대로 비즈니스 로직이 들어가면 안되고 오직 도메인 객체를 불러와 작업을 위임하고 트랜잭션을 관리하는 흐름 제어 역할 +- Domain Layer + - model에 해당 + - 엔티티를 활용하여 도메인 로직이 실행되며, 업무 상황을 반영하여 상태를 제어하는 역할 +- Infrastructure Layer + - Repository에 해당 + - db등 외부와 통신해서 얻어 온 정보를 도메인 계층, 응용 계층 등에 전달하는 것이 주목적 + +| **구분** | **도메인형 아키텍처** | **DDD (도메인 주도 설계)** | +| --- | --- | --- | +| **정체** | 코드를 담는 **패키지 구조** | 소프트웨어를 설계하는 **거대한 방법론** | +| **핵심** | `Controller`, `Service` 등을 역할이 아닌 **기능(User, Mission 등) 단위로 같은 폴더에 묶음** | 현실의 비즈니스 규칙을 응용 계층(Service)이 아닌 **도메인 객체(Entity, Aggregate) 안에 직접 구현**함 | +| **목적** | 유지보수 편하게 | 복잡한 비즈니스 규칙 캡슐화 → 데이터의 일관성 | + +### 왜 DTO를 사용하는가? +### DTO + +계층 간 데이터 교환을 위해서 사용하는 객체 +로직을 가지지 않고 순수하게 데이터를 주고 받을 수 있도록 Getter, Setter만 가짐 + +**<사용 목적>** + +- entity와의 결합도 낮추기 + - Entity는 데이터베이스의 테이블과 1:1로 매핑되는데 이를 api 응답으로 바로 사용하게 된다면 후에 데이터베이스의 구조나 칼럼명이 바뀔 때마다 api도 바뀌게 됨 +- 민감한 정보 숨기기+클라이언트에게 딱 맞는 데이터 제공 + - DB와 연결된 Entity 객체를 바로 클라이언트에게 주기에는 민감한 정보나 화면에 필요 없는 정보 등이 있을 수 있으니 DTO로 필요한 정보만 담아서 준다 +- 입력값 검증 책임 분리 + - 비즈니스 로직을 entity에 붙이지 않고 DTO에서 해결해서 entity는 비즈니스 로직에만 집중하게 한다 +- 클라 - 서버 호출 최소화 + - 여러 개의 api가 필요할 때 거기서 필요한 모든 데이터들을 가진 DTO 하나만 보낸다면 호출 비용을 최소화 가능 + +### 컨버터는 왜 사용하는가? +### **컨버터** + +- Entity를 DTO로 변환하거나, 반대로 DTO를 Entity로 변환하는 매핑 로직만을 전담하는 객체 + +**<사용 목적>** + +- **단일 책임 원칙(SRP) 준수 및 서비스 코드 정돈** + - Service 계층은 비즈니스 흐름을 제어하는 본연의 역할에만 집중해야 함 + - 데이터를 하나하나 옮겨 담는 단순 매핑 코드를 컨버터로 분리하여, Service 코드가 노가다성 코드로 지저분해지는 것을 방지 +- **코드 재사용성 극대화 (중복 방지)** + - 단건 조회, 전체 목록 조회, 추천 조회 등 여러 API에서 동일한 DTO 변환이 필요할 때, 세팅 코드를 복사/붙여넣기 할 필요 없이 컨버터의 메서드 한 줄로 재사용 가능 +- **유지보수의 편의성 (수정 범위 최소화)** + - 추후 요구사항이 변경되어 DTO에 새로운 데이터 필드가 추가될 경우, 해당 DTO를 사용하는 모든 `Service` 파일을 일일이 찾아 고칠 필요 없이 컨버터 클래스 딱 한 곳만 수정하면 전체 시스템에 일괄 적용됨 \ No newline at end of file diff --git a/mission/chapter03/mission.md b/mission/chapter03/mission.md index 6a34d0f..3c2e9fe 100644 --- a/mission/chapter03/mission.md +++ b/mission/chapter03/mission.md @@ -1,3 +1,16 @@ +### 워크북 캡쳐 + +![워크북.png](워크북.png) + +### 워크북 리뷰 + + + - **미션 기록** ### 스프링의 요청 및 응답 흐름 (Spring MVC 흐름) diff --git "a/mission/chapter03/\354\233\214\355\201\254\353\266\201.png" "b/mission/chapter03/\354\233\214\355\201\254\353\266\201.png" new file mode 100644 index 0000000..49bed88 Binary files /dev/null and "b/mission/chapter03/\354\233\214\355\201\254\353\266\201.png" differ