Bonjour, l'article d'aujourd'hui aborde un point de vue apparemment impopulaire, et je suis sûr qu'il rencontrera une certaine résistance. Ce n’est pas parce que quelque chose est techniquement réalisable qu’il est automatiquement utile ou adapté. Par conséquent, je vais tenter de justifier pourquoi je pense que l’utilisation de Lombok pourrait nuire à votre code.
Avant d'entrer dans les détails les moins populaires, permettez-moi de vous proposer une explication concise du fonctionnement de la bibliothèque de Lombok.
Le Projet Lombok agit comme une bibliothèque qui injecte du code dans une classe au moment de la compilation, ce qui peut paraître presque magique. Pour comprendre ses opérations, comprendre le processus de compilation Java est essentiel. La compilation Java comporte trois étapes principales (Figure 1) : Analyser et saisir, Traitement des annotations, Analyser et générer, comme illustré dans le diagramme suivant :
Figure 1 – Arbre de syntaxe abstraite (AST)
Analyser et saisir :
Ici, le compilateur convertit les fichiers source en un arbre de syntaxe abstraite (AST). Les erreurs ne sont générées qu'en cas de syntaxe non valide, et non en cas d'utilisation incorrecte d'une classe ou d'une méthode.
Traitement des annotations :
Au cours de cette phase, les processeurs d'annotations personnalisés valident les classes ou génèrent de nouvelles ressources comme des fichiers sources. Cela peut déclencher un nouveau cycle de compilation si de nouvelles sources sont générées.
Analyser et générer :
Dans cette étape finale, le compilateur produit du bytecode à partir de l'AST, vérifie les références brisées, vérifie les flux logiques, effectue l'effacement de type et désucre le sucre syntaxique.
Le projet Lombok fonctionne comme un processeur d'annotations, modifiant l'AST en injectant de nouvelles méthodes, champs ou expressions. Contrairement aux processeurs classiques qui génèrent de nouvelles sources, Lombok modifie les classes existantes, une distinction qui lui permet d'avoir un impact direct sur le bytecode généré.
AnnotationProcessor introduit dans J2SE 1.5 ne peut pas apporter de modifications aux fichiers existants. Il ne pouvait créer que de nouveaux fichiers ou bytecode. Cela rend l'implémentation de Lombok intrigante, car ils utilisent AnnotationProcessor pour modifier les fichiers de classe Java existants, pendant la phase de compilation. Voici un aperçu du
processus de compilation avec Lombok (Figure 2).
Figure 2 – Processus de compilation et Lombok
Après avoir compris la magie derrière Lombok, examinons les raisons pour lesquelles je pense que cela pourrait être préjudiciable à votre base de code.
Les opérations de Lombok au moment de la compilation allongent inévitablement le processus de compilation, particulièrement prononcé dans les bases de code plus volumineuses en raison de la gestion accrue de l'AST requise.
Lombok propose diverses annotations qui peuvent donner l'illusion de résoudre des problèmes de programmation fondamentaux. Je discuterai de certaines de ces annotations que je rencontre fréquemment dans la base de code.
L'annotation @Builder dans Lombok simplifie la création d'objets grâce au modèle de construction, ajoutant une couche de commodité initialement attrayante. Prenons cet exemple :
@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; }
Et son utilisation :
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); } }
Bien que le modèle de construction soit mis en œuvre efficacement, des questions cruciales sur l'intégrité et la validité des objets créés sont soulevées.
Quel type de cours instancions-nous si nous omettons le .type() dans le constructeur ?
Cette ligne de code serait compilable, mais elle nous laisse perplexe : quel type de cours avons-nous réellement créé ? Est-ce une instance de cours valide ?
Course.builder().id(1L).build();
Ces préoccupations suggèrent que les développeurs, peut-être influencés par la commodité des annotations, pourraient négliger la modélisation de domaine approfondie nécessaire au maintien de l'intégrité de la logique métier. Au lieu de laisser Lombok dicter notre conception, une approche plus réfléchie garantissant l'alignement avec les exigences de l'entreprise est cruciale.
Envisagez d'ajuster la mise en œuvre pour vous assurer que toute création de cours est claire et contrainte dans le contexte métier :
@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); } }
En repensant la classe :
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); } }
La conception révisée garantit que la création d'objets de cours est explicite et infaillible, reflétant les choix contraints inhérents au domaine et éliminant toute ambiguïté.
De plus, en rendant l'énumération Type privée et en fournissant des méthodes claires et explicites comme isOnline() et isOnsite(), nous garantissons que seuls les états valides sont exposés et manipulés, préservant ainsi l'intégrité du domaine.
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.
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) {}
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.
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.
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.
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.
L'utilisation de Lombok peut entraîner des complications lors de la création de projets avec des outils qui utilisent uniquement les options standard du compilateur Java. Par exemple, si votre code utilise des getters et des setters générés par Lombok, la compilation directement avec javac sans prétraitement Lombok pourrait entraîner des erreurs indiquant des méthodes manquantes. Même si certains peuvent considérer la capacité de Lombok à injecter du code comme une "astuce" intelligente, il est essentiel d'évaluer de manière critique les risques et les alternatives associés. Le cœur du problème réside dans le fait que la spécification de traitement des annotations de Java ne prend pas officiellement en charge la modification des classes existantes lors de la compilation. S'appuyer sur ces techniques non officielles rend Lombok vulnérable aux futures mises à jour Java qui pourraient potentiellement perturber ou désactiver ses fonctionnalités.
En fin de compte, ces considérations soulignent l'importance d'évaluer non seulement les avantages immédiats d'outils comme Lombok, mais également leurs implications à long terme sur la maintenabilité, la compatibilité et l'alignement avec les normes Java. À mesure que Java continue d'évoluer, le recours à des fonctionnalités stables et standardisées devient de plus en plus critique pour garantir la durabilité et la fiabilité de vos projets logiciels.
Lombok peut sembler être un raccourci pratique pour le développement Java, mais il déplace le code Java vers une version spécifique au domaine que j'aime appeler "Lombok Java". Il est essentiel de réaliser que s'appuyer excessivement sur Lombok peut obscurcir l'essence de Java, conduisant potentiellement à un code moins robuste et plus difficile à gérer sans les béquilles de Lombok.
Si une dépendance excessive à Lombok est la solution pour gérer votre base de code, il est peut-être temps de réévaluer l'architecture et les pratiques sous-jacentes. La véritable force de Java réside dans sa clarté et sa structure, et non dans les raccourcis fournis par les bibliothèques externes.
Si j'en avais l'occasion, je choisirais de supprimer Lombok de mes projets.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!