[Java] Record를 비즈니스 로직에 지양해야 하는 이유

Daon (HyeongIk Jo)·2024년 3월 10일
6

개글스

목록 보기
3/8
post-thumbnail

오늘은 Record를 비즈니스 로직에 지양해야 하는 이유에 대해 알아보려 한다.
그 전에 간단한 개념부터 알아보자

Record란

레코드의 등장 이유는 JEP 359를 통해 확인할 수 있다.

Enhance the Java programming language with records. Records provide a compact syntax for declaring classes which are transparent holders for shallowly immutable data. This is a preview language feature in JDK 14.

요점은 compact syntaximmutable이다.


Record 등장 이전 일반적으로 불변 객체는 아래와 같이 사용했었다.

public class Person {
	private final String name;
    private final int age;
    
    public Person(String name, int age) {
    	this.name = name;
        this.age = age;
    }
    
    public getName() {
    	return name;
    }
    
    public getAge() {
    	return age;
	}
    
    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Person)) return false;
        Person point = (Person) o;
        return this.name.equals(o.name) && this.age == o.age;
    }

	@Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

	@Override
    public String toString() {
        return String.format("Person[name=%s, age=%d]", name, age);
    }
}

이 코드에는 문제가 있다. 각 클래스에 대해 동일한 프로세스를 반복해야 한다. equals, hashCode 및 toString 메서드를 생성하고, 각 필드를 받아들이는 생성자를 생성해야 한다.
또, 새 필드를 추가할 때 클래스를 이러한 메서드를 일일이 수정해줘야 한다.

Record는 불변 객체의 이러한 단점을 해결해 주었다.

public record Person(String name, int age) {}

특징

컴팩트 생성자(Compact Constructor)

  • Record는 매개 변수를 받는 부분이 없는 컴팩트 생성자를 가진다.

    public record Person(String name, int age) {
        public Person {
          Objects.requireNonNull(name);
        }
    }
  • 주로 유효성 검증이나 간단한 초기화 작업을 수행한다.

  • 레코드 헤더와 동일한 시그니처를 갖는 생성자는 같이 사용할 수 없다.

    public record Person(String name, int age) {
    	// 같이 사용 불가
    	public Person {
    		Objects.requireNonNull(name);
    	}
    
    	public Person(String name, int age) {
      		this.name = name;
    		this.age = age;
    	}
    }

Record는 다른 클래스를 상속 또는 확장할 수 없다.

  • Record가 암시적으로 final이며 abstract가 불가능 하기 때문이다.
class Ape {}

// compile error
record Person(String name) extends Ape { 
}

// compile error
class Daon extends Person { 
    Daon(String name) {
        super(name);
    }
}
  • 인터페이스를 구현하는 것은 가능하다.

private final fields 이외의 인스턴스 필드를 선언할 수 없다.

// compile error
record Person(String name) { 
	int age;
}
  • 선언되는 다른 모든 필드는 static 이어야 한다

비즈니스 로직이란

Robert Sheldon은 다음과 같이 비즈니스 로직을 설명한다.

In programming, business logic is the part of a software program responsible for implementing the business rules that define how data should be created, modified, transformed, communicated and in other ways managed and controlled.

요약하면 비즈니스 로직은 데이터를 생성, 수정, 변환, 전달하는 방법과 기타 방식으로 관리 및 제어하는 방법을 정의하는 비즈니스 규칙이다.


Record를 비즈니스 로직 사용에 지양해야 하는 이유

1. 코드를 이해하고 유지보수하기 어렵다.

위에서 설명했듯이 비즈니스 로직은 종종 데이터를 조작 및 연산을 포함한다. 이를 표현하기 위해서는 Record 내부에 로직을 포함해야 한다.
이 경우 데이터만을 표현해야하는 Record의 초점을 잃어 코드를 이해하고 유지 보수하는데 어려움을 준다.

2. 상속 및 확장이 어렵다.

기본적으로 final인 성질 때문이다. 명시적으로 상속이 불가능하니 확장이 어렵다는 것을 의미한다. 비즈니스 로직에서 기능을 확장하거나 재사용해야 하는 경우에 유연성이 제한됨을 말한다.


정리

그렇다면 도메인 내 데이터를 연산/조작하지 않는 클래스는 표현해도 되지 않을까란 의문이 남는다.
이에 대한 개인적인 견해는 다음과 같다.

  • 비즈니스 로직은 언제 어떻게 변할지 모른다.
  • 만약 요구사항이 변경된다면 위의 1번 이유를 근거로 record를 삭제하고 다시 클래스로 나타내야 한다.
    • 결국 두번 작업하는 꼴이 된다.

만약 잘못된 내용이나 질문이 있는 경우 댓글로 남겨주길 바란다.


참고 문서

Java 14 Record Keyword
oracle
jdk359
What is business logic and how does it work?-Robert Sheldon
Record Keyword in Java-Junhyunny's Devlogs
[Java] Java14 레코드(Record)를 알아보자-곰민

profile
To be a Backend Developer

0개의 댓글

관련 채용 정보