ホームページ  >  記事  >  Java  >  Lombok は Java プロジェクトから削除されるべきだと私が考える理由

Lombok は Java プロジェクトから削除されるべきだと私が考える理由

PHPz
PHPzオリジナル
2024-09-03 14:01:08719ブラウズ

こんにちは、今日の記事は一見不人気な見解に取り組んでいますが、多少の抵抗に遭うことは確実です。技術的に実現可能だからといって、その有用性や適合性が自動的に保証されるわけではありません。したがって、Lombok を使用するとコードに悪影響を及ぼす可能性があると私が考える理由を実証してみます。

魔法の解明: プロジェクト ロンボクを理解する

あまり知られていない詳細を掘り下げる前に、Lombok ライブラリがどのように機能するかについて簡潔に説明しましょう。

Project Lombok は、コンパイル時にクラスにコードを挿入するライブラリとして機能します。これはほとんど魔法のように見えるかもしれません。その動作を理解するには、Java のコンパイル プロセスを理解することが不可欠です。 Java コンパイルには、次の図に示すように、解析と入力、注釈処理、分析と生成の 3 つの主要な段階 (図 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 は、既存のファイルを変更できません。新しいファイルまたはバイトコードを作成することしかできませんでした。これにより、lombok の実装は興味深いものになります。コンパイル段階で AnnotationProcessor を使用して既存の Java クラス ファイルを変更するからです。
の概要は次のとおりです。 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();

これらの懸念は、開発者がおそらくアノテーションの利便性に振り回されて、ビジネス ロジックの整合性を維持するために必要な徹底的なドメイン モデリングを見落とす可能性があることを示唆しています。ロンボク島に設計を委ねるのではなく、ビジネス要件との整合性を確保する、より考慮されたアプローチが重要です。

コースの作成がビジネス コンテキスト内で明確かつ制約されるように、実装を調整することを検討してください。

@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);
    }
}

改訂された設計により、Course オブジェクトの作成が明示的かつ確実に行われるようになり、ドメイン固有の制約された選択肢が反映され、曖昧さが排除されます。

さらに、Type enum をプライベートにし、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.

Java標準

標準 Java コンパイラ オプションのみを使用するツールでプロジェクトを構築する場合、Lombok を使用すると複雑な問題が発生する可能性があります。たとえば、コードが Lombok によって生成されたゲッターとセッターを利用している場合、Lombok の前処理を行わずに javac で直接コンパイルすると、メソッドが欠落していることを示すエラーが発生する可能性があります。コードを挿入する Lombok の機能を巧妙な 「トリック」 と考える人もいるかもしれませんが、関連するリスクと代替案を批判的に評価することが重要です。問題の核心は、Java のアノテーション処理仕様がコンパイル中の既存クラスの変更を正式にサポートしていないという事実にあります。これらの非公式テクニックに依存すると、Lombok は将来の Java アップデートに対して脆弱になり、その機能が中断または無効になる可能性があります。

最終的に、これらの考慮事項は、Lombok のようなツールの当面の利点だけでなく、保守性、互換性、Java 標準との整合性に対する長期的な影響も評価することの重要性を強調しています。 Java が進化し続けるにつれて、ソフトウェア プロジェクトの持続可能性と信頼性を確保するために、安定した標準化された機能への依存がますます重要になってきます。

結論

Lombok は Java 開発にとって便利なショートカットのように思えるかもしれませんが、Java コードを、私が 「Lombok Java」 と呼ぶドメイン固有のバージョンに移行します。 Lombok に過度に依存すると、Java の本質が曖昧になり、コードの堅牢性が低下し、Lombok の杖なしでは管理が難しくなる可能性があることを認識することが重要です。

Lombok に過度に依存することがコードベース管理の解決策である場合は、基盤となるアーキテクチャとプラクティスを再評価する時期が来たかもしれません。 Java の真の強みは、外部ライブラリによって提供されるショートカットではなく、その明瞭さと構造にあります。

機会があれば、私は自分のプロジェクトからロンボク島を除外することを選択します。

以上がLombok は Java プロジェクトから削除されるべきだと私が考える理由の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。