빌더 패턴이 정말로 좋을까

2025. 3. 24. 16:58·Side Tech Notes

이전에 썼던 정적 팩토리 메소드 글과 마찬가지로 스터디 초반에 빌더 패턴을 적용하는 분이 많아서 빌더 패턴에 대한 제 생각을 적은 글입니다. 결론적으로 저는 빌더 패턴도 지양하는 편입니다.

빌더 패턴이란?

빌더 패턴은 복잡한 객체들을 단계별로 생성할 수 있는 디자인 패턴입니다. 대표적으로 스프링의 ResponseEntity가 있는 것 같습니다.

ResponseEntity.ok()
      .header(HttpHeaders.AUTHORIZATION, jwtToken.accessToken())
      .header(HttpHeaders.SET_COOKIE, refreshTokenCookie.toString())
      .build();

이렇게 클래스를 생성할 때 생성자를 통해 생성하는 것이 아닌 빌더라는 객체를 통해 클래스를 생성하는 방식을 빌더 패턴이라고 합니다.

빌더 패턴을 검색해보면 빌더 패턴의 장점을 소개하는 여러 글이 나옵니다. 해당 글들의 대표적인 빌더 패턴의 장점을 보면

  1. 생성자의 파라미터가 많다.
  2. 필요한 데이터만 세팅해 줄 수 있다.

위 2가지인 것 같습니다. 이제 하나하나 살펴보면서 제가 빌더 패턴을 지양하는 이유를 설명하겠습니다.

1. 생성자의 파라미터가 많다?

이 이유가 가장 대표적인 이유인 것 같습니다. 스터디에서 만난 분들도 해당 이유를 가장 많이 듭니다. 생성자의 파라미터가 많으면 무슨 단점이 있냐고 물어보면 전부 같은 자료형의 파라미터가 여러 개 있을 때 각 파라미터가 무엇을 의미하는 지 이해하기 힘들고 해당 부분을 컴파일에서 잡아주지 않아서 만약 순서가 바뀌면 오류가 발생할 수 있다라고 말합니다.

public class User {

    private final String name;
    private final String email;
    private final String address;
    private final int age;
    private final int height;
    private final int weight;

    public User(String name, String email, String address, int age, int height, int weight) {
        this.name = name;
        this.email = email;
        this.address = address;
        this.age = age;
        this.height = height;
        this.weight = weight;
    }
}

이렇게 생성자에 파라미터가 여러개 있으면 사용하는 입장에서 첫번째 String이 이름인지 두번째 String이 이메일인지 이해하기 힘들어서 빌더 패턴을 도입한다고 합니다.

하지만 저는 아래와 같은 이유로 빌더 패턴을 도입하는 것은 강하게 반대합니다.

1. IDE의 발달로 전혀 문제가 되지 않는다.

요즘 IDE가 발달했기 때문에 Mac은 Command  + P, Windows는 Ctrl + P를 통해 파라미터를 한 눈에 확인할 수 있고, 심지어 현재 파라미터가 몇번째 파라미터인지도 한눈에 확인할 수 있습니다.

위의 사진처럼 현재 파라미터가 무엇을 의미하는 지 파악하기 쉽기 때문에 생성자의 파라미터가 많다고 빌더 패턴을 도입하는 것은 리소스 낭비라고 생각합니다.

2. 생성자의 파라미터가 많다면 리팩토링의 신호일 수 있다.

객체지향을 배우면서 중요하게 여기는 것 중 하나가 각 클래스의 역할과 책임을 적절히 분리하는 것 입니다. 하나의 클래스에 너무 과한 책임이 부여되면 코드를 이해하기 힘들고 로직의 변화에 코드의 변경사항이 많아질 확률이 높습니다. 그렇기에 클래스의 책임이 과해진다고 판단되면 리팩토링을 통해 클래스의 책임을 덜어줄 필요가 있습니다.

저는 클래스의 책임이 과한지 판단할 수 있는 기준 중 하나가 필드의 개수라고 생각합니다. 만약 클래스의 필드가 많다면 해당 클래스에 너무 책임이 과해 리팩토링을 하라는 신호일 수 있습니다.

따라서 클래스의 필드가 많아서 생성자의 파라미터가 많다고 바로 빌더 패턴을 적용하는 것은 잘못된 흐름이라고 생각합니다. 만약 클래스의 필드가 많아서 생성자의 파라미터가 많다면 해당 클래스의 책임이 과하지 않은지, 클래스를 분리해야 되지 않은지 파악하는게 먼저라고 생각합니다.

2. 필요한 데이터만 세팅해 줄 수 있다?

구현을 하다보면 상황에 따라 값이 불필요한 필드가 생기기도 합니다.

public class User {

    private final String name;
    private final String email;
    private final String address;
    private final Integer age;
    private Integer height;
    private Integer weight;

    public User(String name, String email, String address, Integer age, Integer height, Integer weight) {
        this.name = name;
        this.email = email;
        this.address = address;
        this.age = age;
        this.height = height;
        this.weight = weight;
    }
}

위와 같은 코드에서 height와 weight는 상황에 따라 값이 필요없을 수도 있으므로 final을 붙이지 않았습니다. 이때 User를 생성하게 된다면 아래와 같이 생성하는 상황이 있습니다.

public User getUser() {
    return new User("이름", "이메일", "주소", 26, null, null);
}

이와 같이 불필요한 null을 파라미터로 넘겨줘야 하거나

public User(String name, String email, String address, Integer age) {
    this(name, email, address, age, null, null);
}

추가적인 생성자 오버로딩을 필요로 하게 됩니다. 하지만 Builder패턴을 사용하게 되면

User.builder()
    .name("이름")
    .email("이메일")
    .address("주소")
    .age(26)
    .build();

이렇게 생성자를 오버로딩하거나 불필요한 값을 넘겨줄 필요없이 구현이 가능하다는 의미입니다.

하지만 위와 같은 상황에서 생성자를 오버로딩 하는 것이 빌더 패턴을 도입할만큼 불필요한 코드일까요?

만약 실제로 불필요한 필드들이 많아 생성자가 여러개 생기게 되면 저도 빌더 패턴을 고민할 것 같습니다.

하지만 그 전에 해당 상황이 리팩토링의 신호일 수 있지 않을까를 먼저 고민해야 된다고 생각합니다.

DB에서 정규화를 중요하게 여기듯이 코드도 비슷하다고 생각합니다.(물론 이 얘기가 클래스와 DB 테이블을 동일시 보는 건 아닙니다. 단순 예시입니다.)

불필요한 필드들이 생길 상황이 많다는 것은 해당 클래스가 해당 필드를 가지는 것은 너무 과한 책임일 가능성이 높을 것 같습니다.

결론

정팩메의 글과 마찬가지로 무조건 빌더 패턴을 사용하지 말자는 글은 아닙니다.

빌더 패턴을 도입하기 전에 진짜로 빌더 패턴을 도입해야만 하는지 고민해보자는 글입니다. 결국 빌더 패턴도 좋은 코드를 고민하다가 나온 디자인 패턴이기 때문입니다.

No Silver Bullet

- Essence and Accident in Software Engineering

'Side Tech Notes' 카테고리의 다른 글

리액터 패턴 / 프로액터 패턴  (1) 2025.07.19
AWS CloudFormation  (0) 2025.05.27
@Transactional과 동시성 제어를 위한 Lock의 관계  (0) 2025.05.23
좋은 코드란 무엇일까 (feat. 객체지향)  (0) 2025.02.21
정적 팩토리 메서드 (정팩메)의 사용에 대해서  (0) 2025.02.16
'Side Tech Notes' 카테고리의 다른 글
  • AWS CloudFormation
  • @Transactional과 동시성 제어를 위한 Lock의 관계
  • 좋은 코드란 무엇일까 (feat. 객체지향)
  • 정적 팩토리 메서드 (정팩메)의 사용에 대해서
ggio
ggio
개발 공부를 하며 배운 내용을 기록합니다.
  • ggio
    기록을 하자
    ggio
  • 전체
    오늘
    어제
    • 분류 전체보기 (41)
      • SW마에스트로 (5)
      • System Architecture (8)
      • Algorithm (15)
      • Side Tech Notes (7)
      • CS (5)
      • 취준 (1)
  • 블로그 메뉴

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

  • 공지사항

  • 인기 글

  • 태그

    리트코드
    fail back
    SW마에스트로
    3PC
    ha 아키텍처
    비관락
    Programming
    leetcode
    at-least-once
    멀티 코어
    코딩테스트
    Algorithm
    알고리즘
    리액터 패턴
    다중화
    시스템 아키텍쳐
    매일메일
    토스 NEXT
    객체지향
    지리적 분산
    소프트웨어 마에스트로
    부트캠프
    fail over
    분산락
    시스템 설계
    프로그래밍
    프로액터 패턴
    소마
    메시지 큐
    코테
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
ggio
빌더 패턴이 정말로 좋을까
상단으로

티스토리툴바