From 783a7ab0bd3a9207a6737f2d0c27cfbbaa5e0a84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=95=88=EC=A4=80=ED=97=8C?= Date: Thu, 20 Feb 2025 09:56:27 +0900 Subject: [PATCH 1/2] "Remove unnecessary column annotations in Member entity" The `@Column` annotations for `key` and `code` fields were redundant and have been removed. This cleanup simplifies the entity definition without affecting functionality. --- .../java/com/mpc/springboot/member/domain/entity/Member.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/spring-boot/src/main/java/com/mpc/springboot/member/domain/entity/Member.java b/spring-boot/src/main/java/com/mpc/springboot/member/domain/entity/Member.java index 0e45e31..4aa7237 100644 --- a/spring-boot/src/main/java/com/mpc/springboot/member/domain/entity/Member.java +++ b/spring-boot/src/main/java/com/mpc/springboot/member/domain/entity/Member.java @@ -9,17 +9,14 @@ @Getter @NoArgsConstructor -//@Table(name = "member") @Entity public class Member { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "`key`") private Integer key; @Convert(converter = MemberCodeConverter.class) - @Column(name = "`code`") private MemberCode code; @Embedded From fa29e0c31c8e27c6d5d8e89aae89dcf0ebd32abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=95=88=EC=A4=80=ED=97=8C?= Date: Thu, 20 Feb 2025 13:38:34 +0900 Subject: [PATCH 2/2] Add detailed documentation on DDD and coding concepts Introduced comprehensive markdown files covering key topics like Domain-Driven Design (DDD), coding best practices, and technical explanations (e.g., dependency management, JPA, Docker). These documents aim to assist developers in understanding and applying core concepts effectively. --- guide/domain-driven-design-Introduction.md | 92 +++++++++++ question/1~3-week-test.md | 183 +++++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 guide/domain-driven-design-Introduction.md create mode 100644 question/1~3-week-test.md diff --git a/guide/domain-driven-design-Introduction.md b/guide/domain-driven-design-Introduction.md new file mode 100644 index 0000000..3f1094c --- /dev/null +++ b/guide/domain-driven-design-Introduction.md @@ -0,0 +1,92 @@ +## 1. 도메인(Domain) +**도메인(Domain)** 은 소프트웨어가 해결하고자 하는 **문제 영역**을 의미합니다. 예컨대 쇼핑몰, 은행 시스템, 병원 예약 시스템 등 구체적인 업무나 사업 영역이 도메인이 됩니다. DDD에서는 이 도메인을 깊이 이해하고, 소프트웨어에 적합한 형태로 모델링하여 **비즈니스 로직**을 올바르게 구현하는 것을 최우선으로 삼습니다. + +--- + +## 2. Ubiquitous Language(보편 언어) +**Ubiquitous Language(보편 언어)** 는 **도메인 전문가(현업 담당자)** 와 **개발자** 사이의 소통에 사용되는 **공통 언어**를 말합니다. +- 예를 들어, “장바구니에 상품을 담는다”라는 도메인 용어를 코드 클래스나 메서드 이름에도 그대로 반영하여, 팀 전체가 **같은 개념과 용어로 의사소통**할 수 있도록 돕습니다. +- 이를 통해 서로 다른 직군 사이에서 용어 정의가 불분명해져 생길 수 있는 **지식 누락**이나 **오해**를 줄일 수 있습니다. + +--- + +## 3. Bounded Context(경계 컨텍스트) +도메인이 커지면, 한꺼번에 모든 것을 처리하기 어렵습니다. 그래서 **의미가 구분되는 맥락**별로 나누어 관리하는데, 이를 **Bounded Context(경계 컨텍스트)** 라고 부릅니다. +- 예를 들어, 대형 쇼핑몰 시스템이라면 “상품 관리”, “주문”, “결제” 등으로 나눌 수 있습니다. +- 각 컨텍스트가 **독립적으로** 자체 모델을 유지하되, 필요한 경우에만 다른 컨텍스트와 **명확한 연동 규칙**을 정의합니다. +- 이를 통해 **불필요한 결합**을 피하고, 각 컨텍스트가 독립적으로 발전∙배포될 수 있도록 유연성을 확보합니다. + +--- + +## 4. Entity, Value Object, Aggregate 등 핵심 개념 + +### 4.1. Entity(엔티티) +- **고유 식별자(ID)** 를 가지며, 해당 식별자를 통해 엔티티의 **생애 주기 전체를 추적**합니다. +- 예: “주문(Order)” 엔티티는 주문 ID로 식별되며, 주문 상태가 바뀌어도 ID가 유지됩니다. + +### 4.2. Value Object(값 객체) +- 별도의 식별자가 없고, **값 자체**가 중요한 객체입니다. +- **불변성**을 강조하며, 값이 변경되면 새로운 Value Object로 대체하는 방식을 권장합니다. +- 예: “주소(Address)” 객체는 식별자보다 그 안의 지역, 도로명, 우편번호 등 **값** 자체가 중요합니다. + +### 4.3. Aggregate(애그리거트) +- 서로 밀접하게 연관된 **엔티티와 값 객체의 집합**입니다. +- 해당 애그리거트의 **루트 엔티티(Aggregate Root)** 를 통해서만 외부에서 접근∙조작할 수 있도록 하여 일관성을 보장합니다. +- 예: “주문(Order)”과 “주문 항목(OrderLine)”들이 하나의 애그리거트를 이룹니다. + +### 4.4. Domain Service(도메인 서비스) +- 특정 엔티티에 속하기 애매하지만, 여전히 **도메인 규칙** 에 해당하는 로직을 모아 둡니다. +- 예: 둘 이상의 애그리거트를 동시에 처리해야 할 경우, 별도의 Domain Service로 추상화하여 책임을 분리할 수 있습니다. + +### 4.5. Repository(리포지토리) +- 엔티티나 애그리거트의 **저장∙조회∙삭제**를 책임지는 컴포넌트입니다. +- DDD에서는 Repository를 통해 도메인 객체를 조작하고, 내부적으로는 JPA나 MyBatis 등 구체적인 DB 기술을 사용합니다. + +--- + +## 5. Context Mapping(맥락 맵핑) +**Bounded Context**가 여러 개 존재할 때, 각 컨텍스트 간 **협력 관계**와 **통신 방식**을 정의하는 것을 **Context Mapping**이라고 합니다. +- 예: “주문 컨텍스트”와 “결제 컨텍스트”가 서로 상호작용할 때, 데이터를 어떻게 넘겨주고 어떤 이벤트를 발생시킬지 정의합니다. +- 필요에 따라 **Anti-Corruption Layer**를 두어 외부 시스템∙컨텍스트와의 데이터 변환∙보호를 수행하거나, **Shared Kernel**로 공통 모델을 공유하는 식으로 모델 통합 방식을 결정합니다. + +--- + +## 6. 도메인 이벤트(Domain Event), Event Storming 등 +### 6.1. 도메인 이벤트(Domain Event) +- “주문이 생성되었다(OrderCreated)”, “결제가 완료되었다(PaymentCompleted)”처럼, **도메인 로직상 중요한 사건**을 이벤트 객체로 표현합니다. +- 이를 발행∙구독(pub/sub) 구조로 설계하면, 컨텍스트 간 **결합도를 낮추고**, **확장성**을 높일 수 있습니다. + +### 6.2. Event Storming +- 도메인 전문가와 개발자가 함께 **시간 축(Time Line)** 순으로 도메인 이벤트를 시각화하여 분석∙설계하는 방법론입니다. +- 포스트잇 등을 활용한 시각화를 통해 **업무 흐름**, **핵심 시나리오**, **잠재적 문제** 등을 빠르게 파악할 수 있습니다. + +--- + +## 7. Subdomain(하위 도메인) +- **Core Subdomain(핵심 하위 도메인)**: 프로젝트에서 가장 중요하고 경쟁력을 만드는 부분입니다. 에너지를 집중 투자해야 합니다. +- **Supporting Subdomain(지원 하위 도메인)**: 핵심을 보조하는 로직이나 기능입니다. +- **Generic Subdomain(범용 하위 도메인)**: 보편적인 기능 예: 결제 모듈, 이메일 전송 등. 필요하다면 제3자 솔루션을 활용하기도 합니다. + +DDD는 **핵심 도메인**에 더 많은 시간을 투자해 비즈니스 가치를 최대화하고, 나머지 부분은 효율적으로 구성해 전체 생산성을 높이는 전략을 지향합니다. + +--- + +## 8. DDD가 추구하는 목표 및 장점 + +1. **복잡한 비즈니스 요구사항에 대한 체계적 접근** + - 핵심적인 문제를 해결하기 위해 도메인을 구조적으로 이해하고, 변화 요구에 대응하기 쉽도록 만듭니다. + +2. **팀 간 원활한 소통** + - Ubiquitous Language를 통해 도메인 전문가와 개발자 간 **용어와 개념**이 일치하도록 돕습니다. + +3. **올바른 추상화와 캡슐화** + - Aggregate 등을 사용하여 핵심 로직을 감싸고, 불필요한 외부 접근을 제한함으로써 **유지보수**가 쉬워집니다. + +4. **확장성과 유연성** + - Bounded Context를 적절히 분리하고, Context Mapping을 통해 **컨텍스트 간 결합도**를 줄여 나갑니다. + +--- + +### 결론 +도메인 주도 설계(DDD)는, **도메인 모델**이 개발 과정 전체에서 최우선이 되도록 하여 복잡한 비즈니스 로직을 **정확**하고 **유지보수 가능**하게 만드는 방법론입니다. +도메인 전문가와 개발자가 **공통 언어**로 끊임없이 소통하면서, **도메인 핵심 가치를 소프트웨어에 반영**하려는 노력이 DDD의 근본이라 할 수 있습니다. \ No newline at end of file diff --git a/question/1~3-week-test.md b/question/1~3-week-test.md new file mode 100644 index 0000000..e545721 --- /dev/null +++ b/question/1~3-week-test.md @@ -0,0 +1,183 @@ +**1. 의존성 관리가 필요한 이유** + +- 라이브러리나 프레임워크가 업데이트되거나 변경될 때, 서로 호환이 보장되도록 버전을 맞추고 충돌을 방지하기 위함 +- 코드가 점점 복잡해짐에 따라, 프로젝트의 안정성과 유지보수를 쉽게 하기 위해 필요 +- e.g. 도메인 모듈(계층)을 나누면, 한 곳의 수정이 다른 곳에 미치는 영향이 최소화된다. + 예를 들어, 도메인 로직을 변경해도 애플리케이션·인프라 레이어는 건드릴 필요가 적다. + 각 레이어의 책임이 분명해 유지보수 범위와 충돌이 줄어든다. + +--- + +**2. 계층(레이어)을 구분해서 설계하는 이유** + +- 책임 분리를 통해 각 레이어가 맡는 역할을 명확히 하고, 코드 가독성과 유지보수를 향상 +- 각 레이어가 독립적으로 변경될 수 있어, 시스템 확장성과 유연성을 높임 + +--- + +**3. Controller, Service, Repository 각 레이어는 어떤 책임을 가지며 어떻게 협력하나요?** + +- **Controller**: 클라이언트 요청을 받고, 적절한 Service를 호출하여 결과를 반환 +- **Service**: 비즈니스 로직을 처리하며, 필요한 경우 Repository를 통해 데이터 접근 수행 +- **Repository**: 데이터베이스와 직접 소통하여 데이터를 조회·저장·수정·삭제 + +--- + +**4. DDD(Domain-Driven Design)의 목표** + +- 소프트웨어의 핵심 복잡도(도메인 로직)를 명확하게 표현하고 해결하기 위함 +- 도메인 모델을 중심으로 팀 간의 공통 언어(Ubiquitous Language)를 형성하여 요구사항과 구현이 일치하게 개발 + +--- + +**5. OOP(Object-Oriented Programming)가 필요한 이유** + +- 객체를 중심으로 책임과 역할을 나누어 설계하면, 코드 재사용성과 유지보수가 좋아짐 +- 캡슐화, 상속, 다형성 등을 통해 복잡도를 낮추고 유연성을 높임 +- e.g. 회원 정보를 다루는 “User” 객체가 “Name”과 “Address” 같은 값 객체를 각각 캡슐화하여 사용한다고 해보겠습니다. + “Name” 객체가 “firstName”, “lastName”을 유효성 검증(빈 문자열 여부, 특수문자 포함 등)하고, “Address” 객체가 “City”, “Street”, “PostalCode”를 검증하도록 분리하면, 이름 형식 변경이나 주소 포맷 변경 등 세부 규칙이 생겨도 관련 객체만 수정하면 됩니다. + 이런 식으로 객체마다 자체적인 검증과 책임을 분명히 두면, 실무에서 규칙이 자주 추가·수정되는 상황에서도 코드를 대폭 갈아엎지 않고도 유연하게 대응할 수 있게 됩니다. + +--- + +**6. .gitignore를 사용하는 목적** + +- 버전 관리가 불필요하거나 보안상 노출되면 안 되는 파일(빌드 결과물, 환경 설정 파일 등)을 Git에서 제외하여 관리 +- 저장소 용량 낭비와 불필요한 충돌을 방지 + +--- + +**7. Docker가 로컬 개발 환경에서 주로 어떻게 쓰이나요?** + +- 특정 버전의 DB나 외부 서비스 환경을 빠르게 구성하여, 개발자가 동일한 환경에서 작업할 수 있도록 지원 +- 여러 프로젝트에서 환경 충돌 없이 독립적인 컨테이너를 구동할 수 있음 + +--- + +**8. Docker의 Image와 Container의 개념과 차이에 대해 설명해주세요.** + +- **Image**: 실행 가능한 환경(파일시스템, 런타임, 설정 등)을 캡슐화한 템플릿 +- **Container**: Image를 실제로 실행한 상태로, 독립된 프로세스로 동작 + +--- + +**9. docker-compose.yml 파일을 작성할 때 유의해야 할 점은 무엇인가요?** + +- 서로 연결될 서비스(컨테이너)의 포트, 볼륨, 네트워크 설정을 명확히 정의 +- 환경 변수나 데이터 볼륨, 버전 정보를 정확히 기재하여 재현 가능하도록 함 +- 여러 컨테이너 간 의존성을 고려하여 실행 순서를 지정하거나, 재시작 정책을 설정 + +--- + +**10. JPA가 하는 역할은 무엇인가요?** + +- 자바 객체와 데이터베이스 테이블 간의 매핑을 자동으로 처리하여, SQL을 직접 다루지 않고도 데이터를 조작할 수 있게 함 +- 데이터 액세스 계층을 단순화하고, 생산성과 유지보수를 높임 + +--- + +**11. JPA에서 Entity 클래스에 주로 사용되는 어노테이션과 그 역할을 설명해주세요.** + +- `@Entity`: 해당 클래스를 JPA가 관리하는 엔티티로 지정 +- `@Table`: 엔티티와 매핑될 테이블 이름 설정 +- `@Id`: 엔티티의 PK(기본 키) 필드 지정 +- `@GeneratedValue`: PK의 자동 생성 전략 지정 +- `@Column`: 테이블의 컬럼 속성(name, nullable, length 등) 지정 +- `@OneToMany`, `@ManyToOne`, `@OneToOne`, `@ManyToMany`: 엔티티 간의 연관관계를 설정 + +--- + +**12. JPA에서 Converter, Embeddable, Auditing 등을 사용하는 이점은 무엇인가요?** + +- **Converter**: 특정 타입을 변환(예: enum ↔ String)하여 DB와 애플리케이션 간에 일관성을 유지 +- **Embeddable**: 재사용 가능한 값 객체를 쉽게 활용해 도메인 모델을 풍부하게 표현 +- **Auditing**: 생성·수정 시점이나 작성자 등을 자동으로 관리해, 공통 요구사항을 중복 없이 처리 + +--- + +**13. 양방향 매핑(ManyToOne, OneToMany) 시 주의해야 할 점은 무엇인가요?** + +- 무한 루프(순환 참조) 방지: 예를 들어, 양쪽에서 같은 엔티티를 직렬화할 때 +- 연관관계 주인 설정: 어느 쪽이 외래 키를 관리하는 주인인지 명확히 해줘야 함 +- 필요 없는 양방향보다는 단방향을 우선 고려하여 복잡도를 낮춤 + +--- + +**14. JPA에서 N+1 문제가 무엇인지 예를 간략하게 적고 해결방법을 설명하세요.** + +- **N+1 문제**: 연관 관계가 있는 엔티티를 조회할 때, 추가로 N번의 쿼리가 발생하여 성능 저하를 일으키는 문제 +- **예시**: Member와 Team 엔티티가 다대일(ManyToOne) 관계일 때, 모든 Member를 조회하고 각 Member의 Team을 LAZY 로딩할 때 발생 + ```java + public void demonstrateNPlusOneProblem() { + // 첫 번째 쿼리: 모든 Member를 조회 + // 예) SELECT m FROM Member m + List members = memberRepository.findAll(); // 1개의 쿼리 + + for (Member m : members) { + // 각 Member마다 Team 정보를 LAZY 로딩하면서 실행되는 쿼리 + // 예) SELECT t FROM Team t WHERE t.id = ? + System.out.println(m.getTeam().getName()); // N개의 쿼리 + } + } + ``` + +- **해결 방법** + - 페치 조인(Fetch Join)을 사용하여 한 번의 쿼리로 모든 연관 엔티티를 함께 조회 + - JPA의 `EntityGraph`를 사용하여 페치 조인을 명시적으로 설정 + - @BatchSize를 사용하여 일괄 처리로 성능을 향상 + +**15. 단위 테스트(Unit Test)는 무엇이며, 왜 필요한가요?** + +- **정의**: 시스템의 가장 작은 단위(주로 메서드나 클래스)의 동작을 검증하는 테스트 +- **필요성**: 빠른 피드백으로 에러를 조기에 발견하고, 리팩토링이나 기능 추가 시 안정성을 제공 + +--- + +**16. 통합 테스트(Integration Test)는 무엇이며, 왜 필요한가요?** + +- **정의**: 여러 컴포넌트나 모듈이 실제로 연결된 상태에서 전체 흐름이 정상 동작하는지 검증하는 테스트 +- **필요성**: 모듈 간 연동 문제, 의존성 문제 등을 조기에 발견해 실제 배포 후 장애를 줄임 + +--- + +**17. Mock은 무엇이며, 어떤 상황에서 왜 사용하는가요?** + +- **정의**: 실제 객체 대신에 비슷한 동작만 흉내내는 ‘가짜 객체’ +- **사용 상황**: 외부 의존성이 있는 코드를 테스트할 때, 네트워크나 DB 같은 복잡한 환경을 대체하여 테스트를 빠르고 독립적으로 진행하기 위해 사용 + +--- + +**18. RESTful한 API를 설계할 때 핵심적으로 고려해야 할 점들은 무엇인가요?** + +- 리소스(명사형) 중심의 URL과 HTTP 메서드(POST, GET, PUT, DELETE)로 명확한 액션 표현 +- 적절한 상태 코드(2xx, 4xx, 5xx)와 에러 메시지 설계 +- 요청과 응답에 일관성 있고 명확한 JSON(or XML) 구조 사용 +- 보안, 버전 관리, 문서화 등도 함께 고려 +- 리소스 간의 관계를 표현하고, 가능하다면 HATEOAS(Hypermedia as the Engine of Application State)를 활용해 API의 자기 기술적인 특성을 활용 + +--- + +**19. DTO를 사용하는 이유는 무엇인가요?** + +- 도메인(Entity) 객체와 API 요청·응답 모델을 분리해, 불필요하거나 민감한 정보 노출을 막을 수 있음 +- 계층 간 데이터 이동 시 변환 로직을 추가하거나, 표시 형식을 자유롭게 조절 가능 + +--- + +**20. Spring Boot에서 전역 예외 처리를 위해 사용할 수 있는 방법은 무엇인가요?** + +- `@ControllerAdvice`와 `@ExceptionHandler`를 사용해 전역적으로 예외를 핸들링 +- `ResponseEntityExceptionHandler`를 상속받아 공통 에러 처리를 구성 +- 필터나 인터셉터 등을 활용해 더 넓은 범위에서 에러 처리를 할 수도 있음 + +--- + +**21. API 서버로 들어오는 다양한 데이터의 포맷(타입)을 핸들링하기 위해 어떤 방법들을 사용할 수 있나요?** + +- RequestParam 혹은 PathVariable의 경우 + - **Spring**에서 `HttpMessageConverter`를 설정하거나 커스텀 Converter를 구현 +- RequestBody의 경우 + - **Jackson**이나 **Gson** 같은 라이브러리를 활용해 JSON/XML 등 다양한 포맷을 직렬화/역직렬화 + - 커스텀 Serializer/Deserializer를 작성해 특정 데이터 타입에 대해 맞춤형 처리를 적용 + +--- \ No newline at end of file