최근 프로젝트를 진행하며 JPA 엔티티를 설계하는 과정에서 왜 특정 어노테이션을 조합해 사용하는지, 그리고 객체 지향적인 설계란 무엇인지 깊게 파고들어 보았습니다. 공부한 내용을 잊지 않기 위해 정리합니다.
1. @NoArgsConstructor(access = AccessLevel.PROTECTED)
JPA 엔티티를 만들 때 가장 먼저 마주친 의문은 "왜 기본 생성자를 굳이 protected로 막는가?"였습니다.
- JPA의 요구사항: JPA는 프록시 객체를 생성하기 위해 기본 생성자가 반드시 필요합니다. 하지만 접근 제어자가 private이면 접근할 수 없으므로 최소 protected 이상이어야 합니다.
- 객체 오염 방지: 개발자가 new Member()와 같이 빈 객체를 생성하는 것을 막기 위함입니다. 필수 데이터가 없는 불완전한 객체가 시스템을 돌아다니는 것을 원천 차단합니다.
- 결론: JPA는 일하게 하되, 개발자의 실수는 막는 절묘한 방어막입니다.
2. @Builder와 생성자의 조합
빈 객체 생성을 막았다면, 객체는 어떻게 만들어야 할까요? 정답은 빌더 패턴입니다.
- 가독성: new Member("홍길동", 20, ...) 처럼 순서에 의존하는 대신 .name("홍길동").age(20)처럼 명확한 코드를 작성할 수 있습니다.
- 안전성: 클래스 레벨이 아닌 생성자 레벨에 @Builder를 붙여, 내가 허용하는 필드만 빌더에 포함하는 정교한 설계가 가능해집니다.
3. @Embeddable & @Embedded (데이터의 부품화)
모든 필드를 하나의 클래스에 다 넣으면 클래스가 너무 비대해집니다. 이때 사용하는 것이 임베디드 타입입니다.
- @Embeddable: 독립적인 테이블이 아닌, 다른 엔티티의 부품이 될 클래스에 사용합니다.
- @AttributeOverrides: 같은 부품을 한 테이블에서 다른 컬럼명으로 쓰고 싶을 때 재정의하여 사용합니다.
- 이점: 코드의 재사용성이 높아지고, 실력 점수 계산 같은 특정 로직을 해당 클래스에 응집시킬 수 있어 객체 지향적입니다.
4. 양방향 연관관계와 데이터 일치
MatchRecord(게임 기록)와 MatchParticipant(참가자)의 관계를 공부하며 가장 헷갈렸던 부분입니다.
- @ManyToOne vs @OneToMany: '다(Many)' 쪽이 외래 키(FK)를 가지는 주인입니다.
- 양방향 데이터 일치의 필요성: DB는 FK 하나로 양쪽을 알지만, 자바 객체는 그렇지 않습니다.
- 연관관계 편의 메서드: matchRecord.getParticipants().add(this);
- 생성자에서 이 코드를 호출함으로써, 내 수첩뿐만 아니라 상대방의 리스트에도 나를 추가해줘야 메모리상에서 데이터 불일치가 일어나지 않습니다.
💡 마치며
단순히 코드를 작동시키는 것을 넘어, "왜 이 어노테이션을 쓰는가?"와 "어떻게 하면 더 안전한 객체를 만들 것인가?"를 고민해 본 시간이었습니다. JPA는 알수록 객체 지향 프로그래밍에 대한 깊은 이해를 요구하는 것 같습니다.
'개발 > 백엔드' 카테고리의 다른 글
| [백엔드 개발기] 실시간 IoT 헬스케어 생체 데이터 파이프라인 구축 및 아키텍처 설계 (2) | 2026.05.08 |
|---|---|
| [Spring Boot] IoT 실시간 모니터링: SSE 통신 원리와 Optional 리팩토링 경험기 (1) | 2026.04.16 |
| 멀티캠퍼스 [현대 이지웰] Spring Boot 활용하여 기본 CRUD 기능 구현 (0) | 2025.12.01 |
| 멀티캠퍼스 [현대 이지웰] 인터페이스 기반 프로젝션이란? (0) | 2025.11.24 |
| 멀티캠퍼스 [현대 이지웰] Spring 어노테이션 기록하기 (0) | 2025.11.18 |