티스토리 뷰

Java

~ByParameter naming 에 대한 고찰

LichKing 2022. 11. 3. 19:05

이전에 builder pattern 에 대한 생각을 포스팅한 적이 있다. 이번엔 무심코 많이 작성하는 ~ByParameter 에 대해 얘기해보고자 한다.

개발자가 가장 많은 시간을 보내는 것은 코드 고민, 코드 작성보다 네이밍이라는 우스갯소리가 있을 정도로 네이밍은 많은 고민이 되는 부분이다. 근데 문제는 부여할 이름 후보가 너무 많아서 고민인게 아니라 도저히 쓸 이름이 없어서 고민인게 문제다. 그러다보니 요즘엔 ~ByParameter 형태의 네이밍을 메서드에 많이 이용하는 것 같다. 특히 service layer 나 repository layer 에서 많이 사용된다.

@Service
public class ProductService {
  private ProductRepository productRepository;

  public Product findById(Long id) {
    return productRepository.findById(id);
  }
}

도저히 이름이 떠오르지 않을때 유용하게 사용할 수 있는 네이밍같은데 어디서 유래했고, 왜 이 포스팅을 작성하게 됐는지 알아보자.

 

# Spring Data Jpa

이런 네이밍의 시작은 Spring Data Jpa 가 제공하는 JpaRepository 에서 시작된 것으로 보인다. 몇년 전만해도 IT 서비스 기업에서도 JPA 는 잘 사용되지 않았는데 언젠가부터 표준으로 사용되면서 Spring Data Jpa 는 Spring 프로젝트에서 필수 모듈이 되었고, 그 이후로 이런 네이밍이 많이 보이기 때문이다. Spring Data Jpa 는 JPA 를 확장하여 다양한 편의기능들을 제공해주는데 대표적인게 메서드 이름을 기반으로 JPQL 을 자동으로 생성해주는 기능이다.

interface ProductRepository implements JpaRepository<Product, Long> {
  // 이렇게만 작성해주면 프레임워크가 자동으로 구현해준다!
  Product findByProductName(String name);
}

아래에선 이 패턴이 왜 문제인지를 설명하겠지만, Spring Data Jpa 가 이 방식을 쓰는 것에 대해선 문제가 없다. 자동으로 JPQL 을 만들어내기 위해서 코드 어딘가에는 쿼리에 대한 힌트가 들어가야했고, 그게 메서드 네임에 들어갔을 뿐이기 때문이다. Spring Data Jpa 는 인터페이스에 정의된 메서드 이름을 파싱하여 쿼리를 생성하게 된다.

 

문제는 대중적인 프레임워크에서 이 방식을 차용하다보니 프레임워크에서 왜 이 방식을 선택했는지에 대한 고민보다는, 이런 네이밍을 무차별적으로 받아들여 비즈니스 코드에도 넣게된 것 같다.

 

# 무엇이 문제인가

프레임워크에서도 채택해서 익숙한 네이밍인데 그럼 이게 왜 문제일까?

 

1. 구현 노출

Spring Data Jpa 는 상술했듯이 JPQL 을 자동으로 만들기 위해 저런 방식을 채용한 것이다. 하지만 프레임워크를 만드는 목적이 아닌 비즈니스 로직에서 ~ByParameter 네이밍은 구현에 대한 노출일 뿐이다. 메서드 네이밍을 지을땐 어떻게 하는지(HOW)가 아니라 무엇을 하는지(WHAT)를 나타내야한다. 하지만 ~ByParameter 는 어떤 파라미터를 사용하는지를 메서드 네임 그 자체에 노출한다. 사실 파라미터 정보는 메서드 이름이 아니어도 파라미터 그 자체에서 나타내게 된다. 메서드 이름과 파라미터는 메서드의 시그니처로써 그 자체로 메서드를 식별한다. 하지만 이름에까지 파라미터 정보를 넣는건 구현에 대한 노출과 어떤식으로 보면 코드 중복으로까지 볼 여지가 있다.

 

2. 변경 취약

~ByParameter 네이밍은 변경에도 무척 취약하다. 사실 구현 노출에서 설명한것과 궤를 같이 하는 내용이다. 메서드 이름에서 구현을 노출하니 구현이 변경되면 메서드 이름까지 변경되어야 하는 것이다.

Product findByProductName(String productName);

위 메서드에서 productName 외에 productPrice 까지 요구하게 된다고 해보자.

Product findByProductName(String productName, int productPrice);
Product findByProductNameAndProductPrice(String productName, int productPrice);

첫번째로 작성하면 규칙 위반이고, 두번째로 작성하면 변경 취약이다. 위에서도 얘기했듯 메서드 시그니처는 메서드 이름과 파라미터로 정해진다. 그래서 파라미터가 변경되면 그 자체로 시그니처는 변경되기 때문에 무엇을 하는지 변경된게 아니라면 단순히 파라미터가 변경됐다고해서 메서드 이름이 영향받을 필요는 없다. 하지만 파라미터 정보를 메서드 이름에 넣는 순간 파라미터와 메서드 이름은 강력하게 결합되어 파라미터만 변경되도 메서드 이름이 변경되어야 한다. 파라미터가 추가되거나 삭제될때는 물론이고, 지역변수로 취급받는 파라미터 이름만 변경되어도 메서드 이름까지 변경이 전파된다.

 

# 정리

Spring Data Jpa 는 매우 편리한 프레임워크고, 나도 애용하고 있다. 하지만 사용하다보면 종종 버리고 싶을때가 있는 프레임워크다. 개인적으로는 특히 대표적으로 이런 네이밍을 전파한게 참 아쉽다(물론 프레임워크의 잘못은 아니다). Spring Data Jpa 는 JPQL 자동생성을 위해 어쩔 수 없이 이런 네이밍을 쓴다는걸 잊지말고, 좀 더 좋은 네이밍을 위해 좀 더 고민해보자.

댓글
댓글쓰기 폼