>Java >java지도 시간 >내가 Lombok을 Java 프로젝트에서 폐기해야 한다고 생각하는 이유

내가 Lombok을 Java 프로젝트에서 폐기해야 한다고 생각하는 이유

PHPz
PHPz원래의
2024-09-03 14:01:08722검색

안녕하세요. 오늘 기사는 겉보기에 인기가 없는 견해를 다루고 있으며, 일부 저항에 부딪힐 것이라고 확신합니다. 어떤 것이 기술적으로 실현 가능하다고 해서 그 유용성이나 적합성이 자동으로 보증되는 것은 아닙니다. 따라서 Lombok을 사용하면 코드에 해로운 영향을 미칠 수 있다고 생각하는 이유를 입증하려고 노력할 것입니다.

마술 공개: 프로젝트 롬복 이해하기

덜 인기 있는 세부 사항을 살펴보기 전에 Lombok 라이브러리의 기능에 대해 간략하게 설명하겠습니다.

Project Lombok은 컴파일 타임에 클래스에 코드를 삽입하는 라이브러리 역할을 하며, 이는 거의 마술처럼 보일 수 있습니다. 해당 작업을 이해하려면 Java 컴파일 프로세스를 이해하는 것이 필수적입니다. Java 컴파일은 세 가지 주요 단계로 구성됩니다(그림 1): 다음 다이어그램에 표시된 대로 구문 분석 및 입력, 주석 처리, 분석 및 생성입니다.

Why I Believe Lombok Should Be Discarded from Java Projects

그림 1 – 추상 구문 트리(AST)

  1. 구문 분석 및 입력:
    여기서 컴파일러는 소스 파일을 AST(추상 구문 트리)로 변환합니다. 잘못된 구문에 대해서만 오류가 발생하며 잘못된 클래스나 메소드 사용에 대해서는 오류가 발생하지 않습니다.

  2. 주석 처리:
    이 단계에서 사용자 정의 주석 프로세서는 클래스의 유효성을 검사하거나 소스 파일과 같은 새로운 리소스를 생성합니다. 새로운 소스가 생성되면 새로운 컴파일 주기가 시작될 수 있습니다.

  3. 분석 및 생성:
    이 마지막 단계에서 컴파일러는 AST에서 바이트코드를 생성하여 끊어진 참조를 확인하고, 논리적 흐름을 확인하고, 유형 삭제를 수행하고, 구문 설탕을 역수거합니다.

Project Lombok은 주석 프로세서로 작동하여 새로운 메소드, 필드 또는 표현식을 삽입하여 AST를 수정합니다. 새로운 소스를 생성하는 일반적인 프로세서와 달리 Lombok은 기존 클래스를 변경하므로 생성된 바이트코드에 직접 영향을 미칠 수 있습니다.

J2SE 1.5에 도입된 AnnotationProcessor는 기존 파일을 변경할 수 없습니다. 새 파일이나 바이트코드만 생성할 수 있습니다. 컴파일 단계에서 AnnotationProcessor를 사용하여 기존 Java 클래스 파일을 수정하므로 lombok의 구현이 흥미로워집니다.
의 개요는 다음과 같습니다. Lombok을 이용한 컴파일 과정(그림 2)

Why I Believe Lombok Should Be Discarded from Java Projects

그림 2 – 컴파일 프로세스 및 Lombok

롬복 사건

Lombok의 숨겨진 마법을 이해한 후, 이것이 코드베이스에 해로울 수 있다고 생각하는 이유를 살펴보겠습니다.

컴파일 시간 증가

컴파일 시 Lombok의 작업은 필연적으로 컴파일 프로세스를 연장하며, 특히 필요한 AST 관리 증가로 인해 대규모 코드베이스에서 두드러집니다.

잘못된 혜택의 의미

Lombok은 기본적인 프로그래밍 문제를 해결하는 듯한 착각을 불러일으킬 수 있는 다양한 주석을 제공합니다. 코드베이스에서 자주 접하는 주석 중 일부에 대해 논의하겠습니다.

  • @Builder 주석

Lombok의 @Builder 주석은 빌더 패턴을 통해 객체 생성을 단순화하고 처음에는 매력적인 편의성을 추가합니다. 다음 예를 고려해보세요:

@Data
@Builder
public class Course {
    public enum Type {
        ONLINE,
        ONSITE;

        @JsonValue
        @Override
        public String toString() {
            return super.toString().toLowerCase();
        }
    }

    private long id;
    private Type type;
}

사용법:

public class CourseCreator {

    public static Course createCourse(Enrollment enrollment, Registration registration) {
        Course.Type courseType = enrollment.getVenue().equals(registration.getVenue()) ? Course.Type.ONSITE : Course.Type.ONLINE;

        return Course.builder()
            .id(enrollment.getId())
            .type(courseType)
            .build();
    }

     public static void main(String[] args) {

        Registration registration = new Registration(); 
        Enrollment enrollment = new Enrollment();
        Course course = createCourse(enrollment, registration);
        System.out.println(course);
    }
}

빌더 패턴이 효율적으로 구현되는 동안 생성되는 객체의 무결성과 유효성에 대한 중요한 질문이 제기됩니다.

빌더에서 .type()을 생략하면 어떤 유형의 강좌를 인스턴스화하나요?

이 코드 줄은 컴파일되지만 우리가 실제로 어떤 유형의 코스를 만들었는가?라는 질문을 남깁니다. 유효한 강좌 인스턴스인가요?

Course.builder().id(1L).build();

이러한 우려는 아마도 주석의 편리함에 휘둘린 개발자가 비즈니스 로직 무결성을 유지하는 데 필요한 철저한 도메인 모델링을 간과할 수 있음을 시사합니다. Lombok이 디자인을 지시하도록 하는 대신 비즈니스 요구 사항에 부합하도록 보다 신중한 접근 방식이 중요합니다.

모든 강좌 생성이 비즈니스 맥락 내에서 명확하고 제한되도록 구현 조정을 고려하세요.

@Data
public class Course {
    private enum Type {
        ONLINE,
        ONSITE;

        @JsonValue
        @Override
        public String toString() {
            return super.toString().toLowerCase();
        }
    }

    public static Course online(long id) {
        return new Course(id, Type.ONLINE);
    }

    public static Course onsite(long id) {
        return new Course(id, Type.ONSITE);
    }

    private long id;
    private Type type;

    public boolean isOnline() {
        return Type.ONLINE.equals(this.type);
    }

    public boolean isOnsite() {
        return Type.ONSITE.equals(this.type);
    }
}

클래스 디자인 변경:

public class CourseManagement {
    public static Course createAppropriateCourse(Enrollment enrollment, Registration registration) {
        return enrollment.getVenue().equals(registration.getVenue()) ? 
            Course.onsite(enrollment.getId()) : 
            Course.online(enrollment.getId());
    }

    public static void main(String[] args) {
        Registration registration = new Registration();
        Enrollment enrollment = new Enrollment();
        Course createdCourse = createAppropriateCourse(enrollment, registration);

        System.out.println(createdCourse);
    }
}

수정된 디자인은 도메인에 내재된 제한된 선택을 반영하고 모호성을 제거하여 강좌 객체 생성이 명시적이고 완벽하도록 보장합니다.

또한 Type 열거형을 비공개로 만들고 isOnline() 및 isOnsite()와 같은 명확하고 명시적인 메서드를 제공함으로써 유효한 상태만 노출 및 조작되어 도메인 무결성을 보호합니다.

Through this thoughtful restructuring, we demonstrate that while tools like Lombok can significantly reduce boilerplate, they are not substitutes for careful design and a deep understanding of the domain. It underscores that Lombok should be employed judiciously, complementing rather than overshadowing robust architectural practices. This ensures that the elegance of our code does not come at the expense of its correctness and clarity.

  • Overreliance on @Setter and @Getter

The argument that getters and setters reduce boilerplate falls short when Java offers alternatives like the Record classes from Java 14.

@Data
public class Movie {
    private String title;
    private int releaseYear;
}

// Can be replaced with:
public record Movie(String title, int releaseYear) {}
  • Superintendent @NonNull

Having null in your code - aside from inputs is generally considered problematic and is often indicative of deeper design issues. The prevalent advice is to avoid returning null whenever possible. Instead, opt for alternatives such as returning non-null collections, utilizing null objects, or throwing exceptions to signify unusual or exceptional conditions. This strategic avoidance means null checks become redundant in most parts of your code.

To distance from Lombok's @NonNull annotation and ensure robustness in Java natively, the Objects.requireNonNull() method from the java.util.Objects class is incredibly useful.
This method streamlines null checking by ensuring that an object is not null, and it throws a NullPointerException with a clear message if it is. This explicit exception-throwing mechanism prevents latent null-related bugs from surfacing in runtime, promoting earlier detection during the development cycle. Here’s an example showing how this method can replace Lombok's functionality

Using Lombok's@NonNull:

public class NonNullExample {
    private Student student;

    public NonNullExample(@NonNull Student student) {
        this.student = student;
    }
}

Equivalent pure Java approach:

import java.util.Objects;

public class NonNullExample {
    private Student student;

    public NonNullExample(Student student) {
        this.student = Objects.requireNonNull(student, "Student cannot be null");
    }
}

This transition to native Java handling enhances code transparency by making the null-check explicit, which is advantageous for code maintenance and understanding.

Constructor Flexibility and Reusability

Constructors play a critical role in how classes interact within your software architecture. A well-designed class should have a variety of constructors that accommodate different use cases, promoting reusability and flexibility. If your constructors merely replicate field assignments, the underlying issue isn't the need to write boilerplate code; rather, it's the risk of fostering a non-reusable and inflexible design that Lombok cannot rectify. Proper constructor design allows a class to be integrated and utilized in a multitude of scenarios, enhancing the overall robustness and adaptability of your codebase.

Evaluating Boilerplate Code: The Lure of Lombok versus Modern Java Features

Lombok's popularity predominantly stems from its ability to reduce boilerplate code, particularly in domain-specific classes like transfer and data objects. While Lombok effectively diminishes the visible clutter by auto-generating necessary code like getters, setters, equals, hashCode, and toString methods, this convenience might obscure potential pitfalls. However, with the advent of Java Records introduced in Java 14, there is a preferable alternative that natively supports the concise declaration of immutable data carriers. Most integrated
development environments (IDEs) are also equipped to automatically generate these boilerplate codes with minimal user input, offering a balance between Lombok’s automation and the control of traditional Java coding.

Compatibility Concerns

Project Lombok's dependency on the underlying Java version poses a significant compatibility risk. As Java evolves, the Abstract Syntax Tree (AST) structure and its interpretation could change, necessitating continuous updates to Lombok to ensure compatibility. This creates a fragile dependency where upgrading to a newer Java version could potentially break your build if Lombok is not simultaneously updated to support these changes. The reliance on unofficial or private APIs to modify class definitions further exacerbates this issue because these APIs could be restricted or altered in future Java releases, threatening Lombok’s long-term viability.

자바 표준

Lombok을 사용하면 표준 Java 컴파일러 옵션만 사용하는 도구로 프로젝트를 빌드할 때 복잡해질 수 있습니다. 예를 들어, 코드가 Lombok에서 생성된 getter 및 setter를 활용하는 경우 Lombok 사전 처리 없이 javac으로 직접 컴파일하면 메소드 누락을 나타내는 오류가 발생할 수 있습니다. 어떤 사람들은 코드를 삽입하는 Lombok의 기능을 영리한 "트릭"으로 간주할 수도 있지만, 관련된 위험과 대안을 비판적으로 평가하는 것이 중요합니다. 문제의 핵심은 Java의 주석 처리 사양이 컴파일 중에 기존 클래스 수정을 공식적으로 지원하지 않는다는 사실에 있습니다. 이러한 비공식 기술에 의존하면 Lombok은 기능을 잠재적으로 방해하거나 비활성화할 수 있는 향후 Java 업데이트에 취약해집니다.

궁극적으로 이러한 고려 사항은 Lombok과 같은 도구의 즉각적인 이점뿐만 아니라 유지 관리 가능성, 호환성 및 Java 표준과의 정렬에 대한 장기적인 영향을 평가하는 것의 중요성을 강조합니다. Java가 계속 발전함에 따라 소프트웨어 프로젝트의 지속 가능성과 신뢰성을 보장하기 위해 안정적이고 표준화된 기능에 대한 의존도가 점점 더 중요해지고 있습니다.

결론

Lombok은 Java 개발을 위한 편리한 단축키처럼 보일 수 있지만 Java 코드를 제가 "Lombok Java"라고 부르는 도메인별 버전으로 전환합니다. Lombok에 과도하게 의존하면 Java 본질이 모호해지고 잠재적으로 Lombok의 도움 없이는 덜 강력하고 관리하기 어려운 코드가 생성될 수 있다는 점을 인식하는 것이 중요합니다.

Lombok에 과도하게 의존하는 것이 코드베이스 관리에 대한 해결책이라면 이제 기본 아키텍처와 방식을 재평가해야 할 때일 수 있습니다. Java의 진정한 강점은 외부 라이브러리에서 제공하는 단축키가 아닌 명확성과 구조에 있습니다.

기회가 주어진다면 내 프로젝트에서 롬복을 제외하겠습니다.

위 내용은 내가 Lombok을 Java 프로젝트에서 폐기해야 한다고 생각하는 이유의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.