바톤 팀이 Java17를 사용하는 이유
0. 들어가기 전에
우테코 팀 프로젝트에서 저희 팀이 자바 버전을 선택한 이유에 대해서 정리해보았습니다.
1. Java11 vs Java 17
자바 버전을 고르기 위해 후보가 몇 가지 있었습니다. 바로 Java 11과 Java 17입니다. 이외에도 Java 1.8과 Java 20도 후보에 올랐었습니다.
Java 1.8은 Java 11에 비해서 부족한 함수(ex) List.of)를 가지고 있고, 기본 GC가 Parallel GC를 사용하므로 11부터 기본 GC로 채택된 G1 GC도 사용하지 않았기 때문에 탈락 했습니다.
Java 20은 현재로서 가장 최신버전이기 때문에, 하위 버전의 장점을 모두 가지고 있고 Java 21로 변경하기 용이하다는 장점이 있었습니다. 하지만 LTS가 아니고 Java 20을 사용하면 23년 9월에 나오는 21로 넘어가기 위해서 사용하기로 했는데 21에 나오는 '가상 스레드 기능을 우리가 사용할까?'' 라는 생각이 있었고, 만약 바로 21로 바꾸면 예상치 못한 문제(호환성 문제)가 발생할 것 같아서 제외했습니다.
이제 남은 Java 11과 Java 17의 차이를 비교해 보겠습니다.
1.1 Java11
우테코에서 지금까지 사용한 가장 친숙한 자바 버전이면서 2022년 기준 가장 많이 사용하는 자바 버전입니다. 가장 많이 사용하는 만큼 기존에 많이 사용하던 Java 8 만큼 reference가 많고 문제가 발생했을 때 트러블 슈팅에 좋다는 장점이 있습니다.
또한 기본 GC로 성능이 향상된 G1 GC를 채택하였고, String 클래스에 나름 쓸만한 strip()
, isBlank()
, repeat()
과 같은 메서드가 추가되었습니다.
1.2 Java17
일단 Java 11보다 지원 기간이 깁니다. Java 11의 지원 기간은 2026.09까지이지만 Java 17은 2029.09까지로 지원 기간이 3년이나 더 깁니다. 현재 가장 길게 지원하는 Java 8이 2030.12까지 지원하기 때문에 별 차이가 나지 않습니다.
두 번째로는 Java 11을 선택했을 때보다 Java 21버전 이상으로 마이그레이션을 했을 때 영향이 최소화되지 않을까 하는 생각이 있었습니다.
세 번째는 새로운 메서드의 추가입니다. Java 12 ~ Java 17까지 많은 메서드가 생겼지만, 그중에서 우리가 사용할 메서드를 뽑아보자면 다음과 같습니다.
1. 텍스트 블록
[As-Is]
@Query("select c from Crew c "
+ "where c.id = :id")
public Optional<Crew> findById(@Param("id") final Long id);
[To-Be]
@Query("""
select c from Crew c
where c.id = :id
""")
public Optional<Crew> findById(@Param("id") final Long id);
다음과 같이 텍스트를 사용할 때 +연산자와 마지막에 띄어쓰기를 안 해도 되기 때문에 좀 더 읽기 좋은 코드를 작성할 수 있고, 실수할 여지가 줄어들 수 있습니다.
2. record
record
는 데이터 클래스를 의미하며 DTO와 같은 클래스를 쉽게 정의할 수 있습니다.. record
의 특징으로는 getter
, toString
, final 클래스
, 모든 필드 private final
, toString 재정의
, equals & hashCode 재정의
가 있다. record
를 사용해서 클래스의 길이가 어떻게 변하는지 살펴보겠습니다.
[As-Is]
public class CrewResponse {
private final String name;
private final int age;
public CrewResponse(final String name, final int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
[To-Be]
public record CrewResponse (
String name,
int age
){}
record를 사용해서 만들었을 때, 클래스 길이가 대폭 줄어든 모습을 볼 수 있습니다. 이렇게 되면 DTO와 같은 반복 작업을 할 때 노동력을 줄일 수 있을 것입니다. Lombok을 사용하면 똑같지 않냐? 라고 반문할 수도 있습니다. 그 말이 맞습니다(?). Lombok을 사용하면 비슷하게 쉽게 만들 수 있습니다. 하지만 외부 라이브러리와 의존적으로 짜인 코드가 과연 좋은 코드일까? 라고 반문하고 싶습니다. 외부 라이브러리에 영향을 받아 우리가 작성한 코드가 바뀔 수 있기 때문입니다. 물론 우리 팀도 Lombok을 사용할 예정이지만, 이러한 이유로 필요한 곳에 필요한 부분만 사용할 예정입니다. Java 17을 사용한다면 최대한 외부 라이브러리에 의존적이지 않게 record를 사용할 것입니다.
3. Stream.toList()
Stream API를 사용할 때, 우리는 Collectors.toList를 사용합니다. 하지만 Java 17은 더 이상 이런 방식으로 사용하지 않아도 됩니다.
[As-Is]
crews.stream()
// 다양한 stream 연산
.collect(Collectors.toList())
[To-Be]
crews.stream()
.toList();
제 경험상 stream에서 Collectors.toList()
를 사용하는 경우가 거의 98% 정도 됩니다. 이 방식을 사용한다면 반복 작업을 상당히 줄여줄 것입니다.
다만, Stream.toList()
는 항상 불변 리스트로 만들어 주기 때문에 이 점을 생각하고 사용해야 합니다.
Stream.toList()
의 내부 구현은 아래와 같습니다.
default List<T> toList() {
return (List<T>) Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())));
}
마지막으로 M1 맥북 정식 지원을 한다는 이유가 있습니다.
우리 팀은 모두 Apple의 M1 맥북을 사용하고 있습니다. 이전 Java 버전은 M1을 정식 지원하지 않기 때문에 내부적으로 로제타를 사용해서 돌아가는 것으로 알고 있습니다. Java 17부터 M1을 정식 지원하기 때문에 이런 불필요한 과정이 줄어들기 때문에 속도가 더 빠를 것이라고 예상됩니다.
2. 결론
위 장단점을 생각해 볼 때, Java 17을 선택하기로 바톤 팀은 결정했습니다. 물론 레퍼런스가 11보다 적긴 하지만, 이 글을 보면 Java 17이 30%가 사용된다고 합니다(중복 선택으로 보임). 또한 Java는 하위 버전의 호환성이 좋은 언어 중의 하나이고, 우리 팀이 사용할 여러 메서드가 추가되었기 때문에 17 버전으로 선택했습니다.
스프링 버전과 관련해서 추가로 글을 쓰려고 했지만, Java 17을 사용하면 Spring Boot 3. x를 사용해야 하므로 2. x와 비교하는 건 어려울 것 같습니다. 우리가 사용할 만한 건 새로 추가된 3.1부터 추가된 docker-compose.yml에서 data source를 설정하는 정도인 것 같습니다. 나중에 시간이 되면 공부해서 올려보겠습니다.
※ 참고
'개발 > [우테코]' 카테고리의 다른 글
바톤의 DB Replication (0) | 2023.10.14 |
---|---|
build 할 때 Rest Docs 파일이 생성이 안되는 문제 트러블 슈팅 (0) | 2023.08.20 |
[Nginx] 하나의 EC2 안에서 React와 Spring 통신하기 (2) | 2023.08.06 |
[Docker] 도커 컨테이너 간 통신 트러블 슈팅 (0) | 2023.07.30 |
[Docker] 바톤 팀 인프라 구조로 알아보는 도커 (0) | 2023.07.23 |