들어가기 전에
Lombok을 선호하지 않는 개발자들이 있다는 걸 안 지는 얼마 되지 않았다. 작년에 처음 듣고 "음, 왜지?" 하면서도 제대로 알아보지 않았었는데 올해 또 듣게 되니까 내가 쓸 때 쓰더라도 어떤 의견들이 있는지 제대로 알고 주관있게 사용해야겠다는 생각이 들었다. 강의를 들으면서 @Data와 같은 어노테이션이 여러 어노테이션을 묶어서 사용하는 거기 때문에 불변해야 할 때 불변함을 유지할 수 없게 만드는 코드가 생성된다던지 하는 우려가 있다는 것은 알았다. 그래도 필요한 어노테이션만 잘 적용해서 쓰면 코드 중복도 줄이고 좋은 거 아닌가 정도로만 생각하면서 깊게 고민해 본 적은 없던 것 같다. 그런데 바로 이게 함정이니 나와 같은 생각을 하시는 분들이라면 이 글을 잘 보시라.
Lombok을 사용하는 이유
그 동안 Lombok을 왜 사용했는가를 생각해 보면 편리하고 깔끔해서였던 것 같다. 내가 필요한 코드를 어노테이션만 적용만 하면 보일러 플레이트 코드를 줄일 수 있어서 코드가 간결해지고 같은 의미의 코드를 반복해서 작성해야 하는 수고로움이 줄기 때문이다. 이전에 블로그에 생성자에 관한 글을 올린 적이 있는데 그때도 빌더 패턴에 대해 작성하면서 Lombok의 @Builder 어노테이션을 사용하면 긴 코드를 작성하지 않고도 편하게 기능을 사용할 수 있다고 말했었다.
참고로 어떻게 이런 일이 가능한가 하면, 어노테이션 프로세서가 일을 하기 때문이다. 이 어노테이션 프로세서는 소스 파일에 있는 어노테이션 정보를 이용해서 컴파일 타임에 새로운 코드를 생성해 주거나 변경해준다. 그런데 어떤 공식적인 API를 통해 작업하는 게 아니라 소스코드를 직접 조작하는 거다 보니 문제가 있다고 들었는데 이 이유로 사용하지 않는다는 이야기는 주변에서 들어보지 못했다.
다른 개발자 분들은 Lombok을 왜 사용할까?
[Java] Lombok이란? 및 Lombok 활용법
Java 언어를 이용해 개발을 하다 보면 기계적으로 작성해야 하는 코드들이 상당히 많다. 이번에는 기계적인 코드 작성을 자동화하여 코드 다이어트를 해주는 Java 필수 라이브러리 Lombok에 대해 알
mangkyu.tistory.com
위의 블로그에서 장점으로 작성된 목록을 가져와봤다.
- 어노테이션 기반의 코드 자동 생성을 통한 생산성 향상
- 반복되는 코드 다이어트를 통한 가독성 및 유지보수성 향상
- Getter, Setter 외에 빌더 패턴이나 로그 생성 등 다양한 방면으로 활용 가능
아마 모두들 나와 같은 마음인 것 같다. 그렇다면 도대체 뭐가 문제인 걸까?
Lombok을 "조심"해야 하는 이유
"Don't use Lombok"을 키워드로 검색해 보면 정말 여러 글들을 볼 수 있다. 그중에 결론이 간결하게 잘 정리된 글이 있어 아래 내용을 가져와봤다.
간단하게 이야기하면, Lombok이 우리를 편하게 해줄 수는 있지만 클린 코드까지 제공하는 것은 아니란 걸 명심하란 거다. 필요한 부분에만 선택적으로 사용하되 확실하지 않은 부분에 대해서는 꼭 문서를 참고하라는 내용이다.
클린 코드를 제공해주지 않는다는 게 무슨 뜻일까? 앞서 언급했듯이 Lombok을 사용하면 자동으로 코드를 생성해 준다. 나는 내 의도에 맞게 어노테이션을 잘 사용했다고 하더라도 정작 코드 상으로 보이는 게 없으니 그 코드를 통해 어떤 문제가 생겨도 알 수 없다는 뜻이다. 이게 내가 말한 함정이다.
@Data
@Data를 사용할 때 우려해야 할 점을 이야기했었는데 만약 그 점을 모르고 사용하는 팀원이 있다면 어떤 문제가 생겼을 때 도대체 어디서 문제가 생긴 건지 모를 가능성이 있다.
다음은 그 상황을 나타낸 예제 코드이다.
// 출처 : https://levelup.gitconnected.com/lombok-to-use-or-not-to-use-that-is-the-blog-e7a3a8f97e8f
@Data
public class HumanName {
private String firstName;
private String lastName;
}
class HumanNameTest {
@Test
void testDuplicate(){
HumanName person1 = new HumanName("first", "second");
HumanName person2 = new HumanName("first", "second");
List<HumanName> humanNameList = Arrays.asList(
person1,
person2
);
Set<HumanName> humanNameSet = new HashSet<>(humanNameList);
assertEquals(2, humanNameList.size());
assertEquals(2, humanNameSet.size());
}
}
@Data는 @EqualsAndHashCode를 포함하고 있기 때문에 위의 테스트 코드가 통과하지 않는다. @Data가 정확히 어떤 기능들을 하는지 모르고 편하다고 쓰면 이 상황에서 어리둥절해질 수밖에 없는 것이다. 참고로 @EqaulsAndHashCode에 적용하고 싶은 필드는 따로 지정해 줄 수 있다(@EqualsAndHashCode(of={“필드명”})). 하지만 모르면 이렇게 점점 클린 코드로부터 멀어질 수 있다.
@AllArgsConstructor
뜨끔했다. @Builder 어노테이션을 사용할 때 @AllArgsConstructor와 @NoArgsConstructor 어노테이션을 계속 같이 사용했었기 때문이다. 테스트 코드를 짤 때 어려움을 겪었다는 분도 계시고, 또 다른 글에서는 필드 선언 순서가 나중에 바뀌면 의도대로 객체를 생성하지 못하는 경우가 생긴다고 했다. @AllArgsConstructor와 @RequiredArgsConstructor 모두 필요한 필드는 직접 만들어서 의존성을 가시적으로 관리해야 혹시 모를 실수를 방지할 수 있으니 사용을 지양하라는 이야기도 있었다.
@Builder
매개변수가 여러 개일때 생성자를 여러 개 만들지 않기 위한 대책으로 Builder를 이야기했었다. 불변성을 유지하면서 선택적으로 변수를 사용할 수 있기 때문이다. 그런데 이 @Builder도 그냥 사용하게 되면 매개변수로 받지 않아도 되는 필드들까지 모두 포함된다. @Getter 어노테이션을 사용할 때처럼 사용하지 않는 필드까지 모두 열어버리게 되는 것이다. 그러니까 매개변수로 사용하지 않아도 되는 필드들은 제외한 생성자를 만들고 클래스가 아닌 생성자 위에 어노테이션을 적용해야 한다.
마무리
확실히 내가 놓치고 있던 것들이 있었다. 특히 클린 코드와 객체 지향적 설계에 대해서 배우고 있는 입장에서 간과하고 있던 사실을 깨닫게 되었다. 그렇지만 Lombok을 사용함으로 인해 발생할 수 있는 문제점을 방지하기 위해 아예 사용하지 않는 것보다는 문제점이 발생할 수 있다는 사실을 인지하고 경계하며 사용하면 된다는 생각에는 변함이 없다. 참고로 JPA나 JaCoCo 사용 시의 주의사항에 관한 글도 있었는데 앞으로 프로젝트에서 둘다 쓰일 거기 때문에 유용한 정보였다. 예전 글들에는 더 많은 문제점들이 적혀져 있는데 지금까지 Lombok에서 그 문제들을 해결했는지는 확인하지 못해서 다 적지는 않았지만, 내가 모르는 문제점이 더 있을 수 있다고 생각하고 항상 의식하면서 사용해야겠다고 생각한다. 편리함에 속아 클린 코드를 잃지 말자!
참고
'노트 > F-lab' 카테고리의 다른 글
NCP 서버 생성부터 ssh 접속까지 (2) | 2023.05.29 |
---|---|
Spring REST Docs를 선택한 이유 (0) | 2023.04.08 |
개발 스펙 정하기 (0) | 2023.03.20 |
F-lab 8주차 (0) | 2023.03.10 |
F-lab 7주차 (0) | 2023.03.02 |