새로운 프로젝트에서 오랜만에 Lombok을 사용하게 됐다. 분명히 @Setter를 추가했는데, 이상하게도 Repository에서 setter가 없다는 오류가 발생했다. 코드를 아무리 살펴보고, 구글링까지 해봤지만 도무지 이유를 찾을 수 없었다.
그러다 "Getter/Setter를 지양하는 방향으로 코드를 작성해야 한다"는 글을 발견했다. 오... 그러면 값 변경은 어떻게 하는건데 라면서 찾아본 Setter의 문제점과 그 대안을 작성 해보려고 한다.
[Setter의 문제점]
Lombok의 @Setter는 코드량을 줄이고 가독성을 높이는 유용한 기능이지만, 무분별한 사용은 객체의 안정성과 유지보수성을 저하 시킬 수 있다. 그래서 최근에는 불변객체 패턴을 선호하는 경향이 있다고 한다.
1. 객체의 불변성 보장 불가
setter가 있으면 객체의 필드 값을 언제든지 변경할 수 있기 때문에 데이터의 일관성이 깨질 위험이 있다.
Member member = new Member();
member.setUserId("user_0115");
member.setUserName("hennie");
// 다른 로직에서 예상치 못하게 값이 변경될 수도 있음
member.setUserId("hackedUser");
이렇게 객체의 필드 값이 아무제약 없이 변경 될 수가 있는데 이런 문제는 멀티스레드 환경이나 데이터 변경이 많은 서비스에서 문제를 불러 일으킬 수 있다.
2. 유지보수성 하락
Setter를 사용하면 필드가 많아 질 수록 객체 생성 및 값 설정 코드가 복잡해진다. 그리고 가독성도 완전 떨어진다.
Member member = new Member();
member.setUserId("user_0115");
member.setUserName("hennie);
member.setEmail("hennie0115@email.com");
member.setPhoneNumber("010-1234-5678");
여기서 어떤 값이 필수고 어떤 값이 선택 사항인지 한눈에 보기 가 어렵다. 또한, 필드 추가시 기존 setter 호출 코드도 작성해줘야 한다.
3. 필수 값 검증이 어려움
Setter 방식에는 필드 값을 하나씩 설정하기 떄문에, 필수 값이 누락될 가능성이 있다.
Member member = new Member();
member.setUserId("user_0115");
// userName을 설정하는 걸 깜빡함...
userName 을 설정하지 않고 객체를 사용하면 예상치 못한 NullPointException이 발생할 수 있다. 객체를 완성되지 않은 상태에서 사용할 가능성이 높아진다.
[해결책]
1. 생성자를 활용하자
@Getter
@AllArgsConstructor
public class Member {
private final String userId;
private final String userName;
}
// 사용 예시
Member member = new Member("user_0115", "hennie");
2. 빌더 패턴을 활용하자
@Getter
@Builder
public class Member {
private final String userId;
private final String userName;
}
// 사용 예시
Member member = Member.builder()
.userId("user_0115")
.userName("hennie")
.build();
[Build 패턴]
1.entity에 @Builder 추가
이렇게 @Builder 를 생성 된 객체는 값이 변경되지 않으므로, 데이터의 무결성을 보장할 수 있다.
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userSeq;
@Column(nullable = false, unique = true)
private final String userId;
@Column(nullable = false)
private final String userName;
}
2. .builder() 를이용하여 가독성과 유지보수의 효율을 높이자
한눈에봐도 코드가 간결하고 어떤 필드가 설정 되어 있는지 알 수 있다.
Member member = Member.builder()
.userId("user_0115")
.userName("hennie")
.email("hennie@email.com")
.phoneNumber("010-1234-5678")
.build();
'spring 스프링' 카테고리의 다른 글
The method builder() is undefined for the type 오류 (해결2) (0) | 2025.04.05 |
---|---|
The method builder() is undefined for the type 오류 (해결1) (0) | 2025.04.04 |
SpringAI 로 OpenAI 의 ChatGPT 만들기 _ 02 (스프링 코드) (0) | 2024.07.29 |
SpringAI 로 OpenAI 의 ChatGPT 만들기 _ 01 (기초세팅) (0) | 2024.07.25 |
이클립스에 스프링 설치하고 스프링부트 프로젝트 생성 (0) | 2024.07.19 |
새로운 프로젝트에서 오랜만에 Lombok을 사용하게 됐다. 분명히 @Setter를 추가했는데, 이상하게도 Repository에서 setter가 없다는 오류가 발생했다. 코드를 아무리 살펴보고, 구글링까지 해봤지만 도무지 이유를 찾을 수 없었다.
그러다 "Getter/Setter를 지양하는 방향으로 코드를 작성해야 한다"는 글을 발견했다. 오... 그러면 값 변경은 어떻게 하는건데 라면서 찾아본 Setter의 문제점과 그 대안을 작성 해보려고 한다.
[Setter의 문제점]
Lombok의 @Setter는 코드량을 줄이고 가독성을 높이는 유용한 기능이지만, 무분별한 사용은 객체의 안정성과 유지보수성을 저하 시킬 수 있다. 그래서 최근에는 불변객체 패턴을 선호하는 경향이 있다고 한다.
1. 객체의 불변성 보장 불가
setter가 있으면 객체의 필드 값을 언제든지 변경할 수 있기 때문에 데이터의 일관성이 깨질 위험이 있다.
Member member = new Member();
member.setUserId("user_0115");
member.setUserName("hennie");
// 다른 로직에서 예상치 못하게 값이 변경될 수도 있음
member.setUserId("hackedUser");
이렇게 객체의 필드 값이 아무제약 없이 변경 될 수가 있는데 이런 문제는 멀티스레드 환경이나 데이터 변경이 많은 서비스에서 문제를 불러 일으킬 수 있다.
2. 유지보수성 하락
Setter를 사용하면 필드가 많아 질 수록 객체 생성 및 값 설정 코드가 복잡해진다. 그리고 가독성도 완전 떨어진다.
Member member = new Member();
member.setUserId("user_0115");
member.setUserName("hennie);
member.setEmail("hennie0115@email.com");
member.setPhoneNumber("010-1234-5678");
여기서 어떤 값이 필수고 어떤 값이 선택 사항인지 한눈에 보기 가 어렵다. 또한, 필드 추가시 기존 setter 호출 코드도 작성해줘야 한다.
3. 필수 값 검증이 어려움
Setter 방식에는 필드 값을 하나씩 설정하기 떄문에, 필수 값이 누락될 가능성이 있다.
Member member = new Member();
member.setUserId("user_0115");
// userName을 설정하는 걸 깜빡함...
userName 을 설정하지 않고 객체를 사용하면 예상치 못한 NullPointException이 발생할 수 있다. 객체를 완성되지 않은 상태에서 사용할 가능성이 높아진다.
[해결책]
1. 생성자를 활용하자
@Getter
@AllArgsConstructor
public class Member {
private final String userId;
private final String userName;
}
// 사용 예시
Member member = new Member("user_0115", "hennie");
2. 빌더 패턴을 활용하자
@Getter
@Builder
public class Member {
private final String userId;
private final String userName;
}
// 사용 예시
Member member = Member.builder()
.userId("user_0115")
.userName("hennie")
.build();
[Build 패턴]
1.entity에 @Builder 추가
이렇게 @Builder 를 생성 된 객체는 값이 변경되지 않으므로, 데이터의 무결성을 보장할 수 있다.
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userSeq;
@Column(nullable = false, unique = true)
private final String userId;
@Column(nullable = false)
private final String userName;
}
2. .builder() 를이용하여 가독성과 유지보수의 효율을 높이자
한눈에봐도 코드가 간결하고 어떤 필드가 설정 되어 있는지 알 수 있다.
Member member = Member.builder()
.userId("user_0115")
.userName("hennie")
.email("hennie@email.com")
.phoneNumber("010-1234-5678")
.build();
'spring 스프링' 카테고리의 다른 글
The method builder() is undefined for the type 오류 (해결2) (0) | 2025.04.05 |
---|---|
The method builder() is undefined for the type 오류 (해결1) (0) | 2025.04.04 |
SpringAI 로 OpenAI 의 ChatGPT 만들기 _ 02 (스프링 코드) (0) | 2024.07.29 |
SpringAI 로 OpenAI 의 ChatGPT 만들기 _ 01 (기초세팅) (0) | 2024.07.25 |
이클립스에 스프링 설치하고 스프링부트 프로젝트 생성 (0) | 2024.07.19 |