[Spring] Setter 사용을 지양해야하는 이유

2025. 8. 29. 21:17·Spring

Setter를 사용하는 이유 

객체 지향의 원칙 중 하나로는 정보 은닉(Information Hiding)이 있다. 객체의 구체적인 정보를 외부에 노출하지 말라는 것이다. 이러한 이유 때문에 자바에서는 클래스를 작성할 때, 모든 필드를 private으로 숨기고 public 메서드를 통해서 간접적으로 필드를 다루게 된다.

public class User {
    private String name;

    public void setName(String name) {
        this.name = name;
    }
}

✅ 그런데 왜 Setter를 사용하면 안되는가 ? 

사실 위에 말들이 굉장히 모순이다. 필드를 private으로 숨겨놓고 Setter를 모두 public으로 열어서 사용하는 것은 정보 은닉의 효과를 볼 수 없다. 필드 자체는 숨겨 놓았는데, Setter로 수정할 수 있다면 이 정보를 정말로 숨겼다고 말할 수 있는건가 ? 그냥 숨겨놓고 다시 열어둔 꼴이 된 거 아닌가 ? 

 

Setter 사용의 문제점 

1) 불변성 (immutability) 깨짐 

불변 객체는 한 번 생성되면 상태가 바뀌지 않아 예측 가능하고 안전하다. 하지만 Setter가 열려 있으면 언제든 외부에서 값을 바꿀 수 있어 신뢰성이 떨어진다.

User user = new User("hong@example.com");
user.setEmail("test@test.com");

 

2) 무결성 (integrity) 훼손 

일부 값은 변경 불가능해야 하는 도메인 규칙을 가지고 있을 수 있다. 예를 들어, 주민등록번호나 계좌번호 같은 값은 객체 생성 시에만 설정되고 이후에는 절대 바뀌면 안된다. 그러나 Setter로 이렇게 바꿀 수 있다면 도메인 규칙이 깨지고 데이터 무결성이 깨진다.

User user = new User("홍길동", "123456-7890123");
user.setResidentId("000000-0000000");

 

3) 캡슐화 (encapsulation) 약화 

캡슐화는 객체 내부의 상태를 숨기고, 외부에서는 의미 있는 동작을 통해서만 접근하도록 만드는 것이다. 하지만 Setter가 무분별하게 열려 있으면 사실상 public 필드와 차이가 없다.

public class BankAccount {
    private int balance;

    public void setBalance(int balance) {
        this.balance = balance;
    }
}

 

4) 유지보수성 저하 

Setter가 많아지면 객체의 상태가 어디서 어떻게 변경되는지 추적하기가 어려워진다. 코드가 복잡해질수록 '이 값이 언제, 어디서, 왜 바뀌었는지' 알 수 없게 된다. 

order.setStatus("PAID");
order.setStatus("SHIPPED");
order.setStatus("CANCELLED");

✅ 그럼 어떻게 해야하는가 ? 

무조건 Setter를 없애라는 건 아니다. 다만 다른 대안을 우선 고려해보자는 것이다. 

 

1) 생성자/빌더를 사용하여 값을 초기화 

객체가 생성될 때 필요한 값들을 모두 전달받아 초기화 시점에 완전한 상태를 보장한다. Setter로 나중에 바꾸지 않아도 되니 불변성을 유지하기 쉽다. 

 

생성자 방식 

public class User {
    private final String email;
    private final String residentId;
    private String name;

    public User(String email, String residentId, String name) {
        this.email = email;
        this.residentId = residentId;
        this.name = name;
    }
}

 

빌더 패턴 

빌더를 사용하면 필수 값과 선택 값을 명확히 나눌 수 있어 가독성과 안정성이 올라간다. 

User user = User.builder()
    .email("hong@example.com")
    .residentId("123456-7890123")
    .name("홍길동")
    .build();

 

 

2) 도메인 메서드 활용 

필드를 직접 바꾸는 Setter 대신, 의미 있는 동작을 수행하는 메서드를 제공한다. 이렇게 하면 도메인 규칙을 코드로 강제할 수 있다.

아래와 같이 예외 처리를 두어서 도메인 규칙을 강제한다. 

public void changeName(String newName) {
    if (newName == null || newName.isBlank()) {
        throw new IllegalArgumentException("이름은 비어있을 수 없음");
    }
    this.name = newName;
}

 

 

3) 불변 객체 활용 

한 번 생성되면 상태가 절대 변하지 않는 객체를 불변 객체라고 한다. 

 

모든 필드를 final로 선언하고 Setter를 두지 않고 값 변경은 무조건 새 객체를 생성하는 방식으로 처리한다. 

public class Address {
    private final String city;
    private final String street;

    public Address(String city, String street) {
        this.city = city;
        this.street = street;
    }

    public String getCity() { return city; }
    public String getStreet() { return street; }
}

마무리 

Setter는 분명 처음 객체 지향을 배울 때는 '정보 은닉을 지키는 안전한 방법' 처럼 보이지만 실제로는 불변성을 깨뜨리고, 무결성과 캡슐화를 훼손한다. 그래서 객체 지향 설계에서는 무분별한 Setter 사용을 지양하고, 생성자나 빌더로 객체를 완전한 상태로 만들거나 의미 있는 도메인 메서드로만 상태를 변경하는 것이 더 바람직하다. 

'Spring' 카테고리의 다른 글

[Spring] Transactional 사용 시 자기 호출(Self-Invocation) 이슈  (0) 2025.09.11
[Spring] Spring Events 사용해 이벤트 발행하기  (0) 2025.09.07
[Spring] DTO class를 record로 사용하는 이유  (0) 2025.08.29
[Spring] 연관관계  (0) 2025.08.29
[Spring] PSA (Portable Service Abstraction)  (0) 2025.08.27
'Spring' 카테고리의 다른 글
  • [Spring] Transactional 사용 시 자기 호출(Self-Invocation) 이슈
  • [Spring] Spring Events 사용해 이벤트 발행하기
  • [Spring] DTO class를 record로 사용하는 이유
  • [Spring] 연관관계
erika0915
erika0915
백엔드 개발자가 되고 싶어요 .
  • erika0915
    erikoding
    erika0915
  • 전체
    오늘
    어제
    • 분류 전체보기 (78)
      • 프로젝트 (13)
        • 끼니콩 (3)
        • 덕메랑 (3)
        • handDoc (7)
        • Haeil (0)
      • Java (9)
        • 클린코더스 (0)
      • Spring (30)
      • Redis (3)
      • CS (7)
        • 운영체제 (3)
        • 컴퓨터구조 (0)
        • 네트워크 (4)
      • DevOps (2)
      • 코딩테스트 (0)
      • Tech (14)
        • TDD (1)
        • 정리 (5)
        • 우테코 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    jira
    CoolSMS
    지라
    redis
    도커
    promtail
    STT
    docker
    자바
    github
    스프링부트
    Spring
    스프링
    Network
    java
    AI
    MongoDB
    springboot
    OS
    몽고디비
    깃허브
    파인튜닝
    깃
    coderabbit
    운영체제
    git
    레디스
    TDD
    코드레빗
    네트워크
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
erika0915
[Spring] Setter 사용을 지양해야하는 이유

티스토리툴바