Arguments contre les annotations

Mon équipe déménage au spring 3.0 et il y a des gens qui veulent tout transférer dans les annotations. J’ai juste un mauvais pressentiment (odeur de code?) Quand je vois une classe qui a des méthodes comme ça: (juste un exemple – pas toutes les annotations réelles)

@Transaction @Method("GET") @PathElement("time") @PathElement("date") @Autowired @Secure("ROLE_ADMIN") public void manage(@Qualifier('time')int time) { ... } 

Est-ce que je suis juste en retard, ou est-ce que tout cela semble être une idée horrible pour quelqu’un d’autre? Plutôt que d’utiliser des concepts OO tels que l’inheritance et le polymorphism, tout est désormais conventionnel ou annoté. Je n’aime tout simplement pas ça. Devoir recomstackr tout le code pour changer les choses que la configuration de l’OMI semble avoir tort. Mais il semble que tout se passe (surtout le spring). Dois-je simplement “surmonter” ou devrais-je repousser et essayer de garder notre code aussi libre d’annotation que possible?

En fait, je pense que le mauvais pressentiment contre votre intuition a plus à voir avec les annotations comme cette configuration de mixage avec le code.

Personnellement, je ressens la même chose que vous, je préférerais laisser la configuration (comme les définitions de transaction, les éléments de chemin, les URL auxquelles un contrôleur devrait être mappé, etc.) en dehors de la base de code et dans les fichiers de contexte XML Spring externes .

Je pense cependant que la bonne approche repose ici sur l’opinion et sur la méthode que vous préférez – je prédirais que la moitié de la communauté serait d’accord avec l’approche des annotations et que l’autre moitié serait d’accord avec l’approche de configuration externe.

Vous avez peut-être un problème avec les annotations redondantes qui sont partout dans le code. Avec les méta-annotations, les annotations redondantes peuvent être remplacées et vos annotations sont au moins DRY.

Du blog de spring:

 @Service @Scope("request") @Transactional(rollbackFor=Exception.class) @Retention(RetentionPolicy.RUNTIME) public @interface MyService { } @MyService public class RewardsService { … } 

Parce que Java évolue si lentement, les utilisateurs ajoutent davantage de fonctionnalités manquantes dans le langage aux annotations. C’est une bonne chose que Java puisse être étendu sous une forme ou une autre, ce qui est une mauvaise chose car la plupart des annotations sont une solution de contournement et ajoutent de la complexité.

Au début, j’étais sceptique quant aux annotations, mais en les voyant, elles peuvent être une bonne chose. Ils peuvent également être surutilisés.

La principale chose à retenir à propos des annotations est qu’elles sont statiques. Ils ne peuvent pas changer à l’exécution. Toute autre méthode de configuration (xml, auto-description dans le code, peu importe) ne souffre pas de cela. J’ai vu des gens ici sur SO avoir des problèmes avec Spring en ce qui concerne la mise en place d’un environnement de test sur les configurations de test d’injection et la nécessité de passer au XML pour le faire.

XML n’est ni polymorphe, ni hérité, ni autre chose, ce n’est donc pas un pas en arrière dans ce sens.

L’avantage des annotations est qu’elles peuvent vous donner plus de contrôle statique sur votre configuration et peuvent éviter beaucoup de problèmes de verbosité et de coordination dans les configurations XML (en gardant essentiellement les choses DRY).

Tout comme XML, les annotations peuvent être surutilisées. L’essentiel est d’équilibrer les besoins et les avantages de chacun. Les annotations, dans la mesure où elles vous donnent moins de code verbeux et DRYer, sont un outil à exploiter.

EDIT: En ce qui concerne le commentaire concernant une annotation remplaçant une classe d’interface ou abstraite, je pense que cela peut être raisonnable à la frontière du framework. Dans une structure destinée à être utilisée par des centaines, voire des milliers de projets, avoir une interface ou une classe de base peut vraiment nuire (en particulier une classe de base, même si vous pouvez le faire avec des annotations, il n’y a aucune raison avec une interface régulière.

Considérez JUnit4. Avant, vous deviez étendre une classe de base qui avait une méthode de configuration et de suppression. Pour ma part, cela n’a pas vraiment d’importance si elles avaient été sur une interface ou dans une classe de base. Maintenant, j’ai un projet complètement séparé avec sa propre hiérarchie d’inheritance et ils doivent tous respecter cette méthode. Tout d’abord, ils ne peuvent pas avoir leurs propres noms de méthodes contradictoires (pas une grosse affaire dans un framework de test, mais vous avez compris). Deuxièmement, vous devez avoir la chaîne d’appel super descendante, car toutes les méthodes doivent être couplées.

Maintenant, avec JUnit4, vous pouvez avoir différentes méthodes @Before dans différentes classes de la hiérarchie et elles peuvent être indépendantes les unes des autres. Il n’y a pas de moyen tout aussi sec pour y parvenir sans annotations.

Du sharepoint vue des développeurs de JUnit, c’est un désastre. Mieux vaut avoir un type défini que vous pouvez appeler setUp et déassembly. Mais un framework n’existe pas pour la commodité du développeur de framework, il existe pour la commodité de l’utilisateur du framework.

Tout cela s’applique si votre code n’a pas besoin de se soucier du type (c’est-à-dire que, dans votre exemple, rien n’utiliserait vraiment un type de contrôleur de toute façon). Ensuite, vous pourriez même dire que l’implémentation de l’interface du framework est plus fluide qu’une annotation.

Si, toutefois, vous allez écrire du code pour lire cette annotation dans votre propre projet, lancez-vous loin.

Vérifiez ces réponses à des questions similaires

Quels sont les avantages / inconvénients des annotations (non-compilateur) par rapport aux fichiers de configuration xml

Configuration Xml versus configuration basée sur Annotation

Fondamentalement, cela se résume à: Utiliser les deux. Les deux ont des casse-têtes. N’utilisez pas d’annotations pour les choses qui devraient restr configurables sans tout recomstackr (en particulier les choses que votre utilisateur devrait pouvoir configurer sans avoir besoin de tout recomstackr)

Personnellement, j’estime que les annotations ont pris trop de place et sont passées de leur but original et super utile (par exemple, des choses mineures comme l’indication d’une méthode surchargée) à cet outil de métaprogrammation insensé. Je ne pense pas que le mécanisme JAva soit suffisamment robuste pour gérer ces groupes d’annotations précédant chaque méthode. Par exemple, je me bats avec les annotations JUnit ces jours-ci parce qu’ils me limitent d’une manière que je n’aime pas

Cela étant dit, dans mon expérience, la configuration basée sur XML n’est pas non plus jolie. Donc, pour citer South Park, vous choisissez entre une douche géante et un sandwich.

Je pense que la principale décision à prendre est de savoir si vous êtes plus à l’aise avec la délocalisation de la configuration de spring (par exemple, conserver deux fichiers au lieu d’un) et si vous utilisez des outils ou des plug-ins IDE bénéficiant des annotations. Une autre question importante est de savoir si les développeurs qui utiliseront ou maintiendront votre code comprendront vraiment les annotations.

Je pense que les annotations sont bonnes si elles sont utilisées avec mesure. Les annotations comme @WebService font beaucoup de travail lors du déploiement et de l’exécution, mais elles n’interfèrent pas dans la classe. @Cachexxx ou @Transactional interfèrent clairement en créant des proxys et de nombreux artefacts, mais je pense qu’ils sont sous contrôle.

Cela commence à gâcher lorsque vous utilisez Hibernate ou JPA avec des annotations et des CDI. Les annotations grandissent beaucoup.

IMO @Service et @Repository sont des interférences de Spring dans le code de votre application. Ils rendent votre application dépendante du spring et uniquement pour une utilisation printanière.

Le cas du graphique de données de spring est une autre histoire. @NodeEntity, par exemple, ajoute des méthodes à la classe au moment de la construction pour enregistrer l’object de domaine. Sauf si vous avez le plug-in Eclipse et Spring, vous rencontrerez des erreurs car ces méthodes n’existent pas dans le code source.

La configuration à proximité de l’object présente des avantages, mais également un sharepoint configuration unique. Les annotations sont correctes avec la mesure, mais elles ne sont pas bonnes pour tout et définitivement mauvaises quand il y a autant de lignes d’annotation que de lignes de code source.

Je pense que le chemin du spring est faux; principalement parce que dans certains cas, il n’ya pas d’autre moyen de faire des choses aussi amusantes. C’est comme si Spring voulait faire du codage xtreme, et en même temps ils bloquent les développeurs dans le framework Spring. Le langage Java a probablement besoin d’une autre façon de faire certaines choses.

Les annotations doivent être utilisées avec parcimonie. Ils sont bons pour certains mais pas pour tous. Au moins, l’approche de configuration xml conserve la configuration dans un fichier (ou plusieurs) au lieu de s’étendre partout. Cela introduirait (comme j’aime l’appeler) l’organisation du code de la merde. Vous ne verrez jamais l’image complète de la configuration si elle est répartie sur des centaines de fichiers.

Comme beaucoup de choses, il y a des avantages et des inconvénients. À mon avis, certaines annotations sont correctes, même si on a parfois tendance à trop utiliser les annotations lorsqu’une ancienne méthode d’appels de fonctions peut être supérieure, et prise dans son ensemble, cela peut augmenter involontairement la charge cognitive parce qu’elles augmentent le nombre de façons de “faire des choses”.

Laisse-moi expliquer. Par exemple, je suis content que vous ayez mentionné l’annotation @Transactional. La plupart des développeurs Spring vont probablement connaître et utiliser @Transactional. Mais combien de ces développeurs savent comment @Transactional fonctionne réellement? Et savaient-ils comment créer et gérer une transaction sans utiliser l’annotation @Transactional? L’utilisation de @Transactional facilite l’utilisation des transactions dans la majorité des cas, mais dans des cas particuliers, lorsque j’ai besoin d’un contrôle plus fin sur une transaction, cela me cache des détails. Donc, d’une certaine façon, c’est une arme à double tranchant.

Un autre exemple est @Profile dans les classes de configuration Spring. Dans le cas général, il est plus facile de spécifier les profils pour lesquels un composant Spring doit être chargé. Cependant, si vous avez besoin d’une logique plus puissante que de spécifier une liste de profils pour lesquels vous voulez charger le composant, vous devez obtenir L’environnement s’objecte et écrit une fonction pour ce faire. Encore une fois, la plupart des développeurs de Spring seraient probablement familiers avec @Profile, mais ils ont de moins en moins connaissance des détails de fonctionnement, comme la fonction Environment.acceptsProfiles (Ssortingng … profiles), par exemple.

Enfin, lorsque les annotations ne fonctionnent pas, il peut être plus difficile de comprendre pourquoi et vous ne pouvez pas simplement placer un point d’arrêt sur l’annotation. (Par exemple, si vous avez oublié le @EnableTransactionManagement sur votre configuration, que se passerait-il?) Vous devez trouver le processeur d’annotation et le déboguer. Avec une approche d’appel de fonction, vous pouvez bien sûr simplement placer un point d’arrêt dans la fonction.

Je pense que cela dépend dans une certaine mesure du moment où vous avez commencé à programmer. Personnellement, je pense qu’ils sont horribles. Principalement parce qu’ils ont des quasi-notions que vous ne comprendrez pas à moins que vous soyez au courant de l’annotation en question. En tant que tels, ils forment eux-mêmes un nouveau langage de programmation et vous éloignent des POJO. Comparé à (disons) le vieux code OO simple. Deuxième raison – ils peuvent empêcher le compilateur de faire votre travail pour vous. Si j’ai une base de code volumineuse et que je veux refactoriser quelque chose ou renommer quelque chose, j’aimerais idéalement que le compilateur mette au point tout ce qui doit être changé ou autant que possible. Une annotation devrait être juste cela. Une annotation. Pas au cœur du comportement de votre code. Ils ont été conçus à l’origine pour être facultativement omis lors de la compilation qui vous indique tout ce que vous devez savoir.

Et oui, je suis conscient que la configuration XML souffre de la même manière. Cela ne le rend pas pire, tout aussi mauvais. Au moins, je peux faire semblant d’ignorer cela – cela ne me regarde pas en face dans chaque méthode ou déclaration de paramètre.

Étant donné le choix, je préférerais les horribles interfaces distantes / domestiques anciennes de J2EE (tellement critiquées par les gens de Spring à l’origine) car cela me donne au moins une idée de ce qui se passe sans avoir à rechercher @CoolAidFrameworkThingy et ses faiblesses. L’un des problèmes avec les frameworks est qu’ils doivent vous associer à leur cadre afin de rendre toute l’entreprise financièrement viable. Ceci est en contradiction avec la conception d’un framework (c.-à-d. Qu’il soit aussi indépendant et amovible que possible de votre code).

Malheureusement, les annotations sont à la mode. Donc, vous aurez du mal à empêcher votre équipe de les utiliser, à moins que vous ne soyez dans les revues de codes / normes et autres (également, hors mode!)

J’ai lu que Stroustup avait laissé des annotations en C ++, car il craignait qu’elles soient mal utilisées. Parfois, les choses vont dans la mauvaise direction pendant des décennies, mais vous pouvez espérer que les choses se dérouleront à temps.

Les annotations introduisent souvent des dépendances où de telles dépendances n’appartiennent pas.

J’ai une classe qui arrive par hasard pour avoir des propriétés qui ressemblent aux atsortingbuts d’une table dans un schéma de SGBDR. La classe a été créée avec cette cartographie en tête. Il y a clairement une relation entre la classe et la table mais je suis heureux de garder la classe libre de toute métadonnée déclarant cette relation. Est-il juste que cette classe fasse une référence à une table et à ses colonnes dans un système complètement différent? Je ne m’oppose certainement pas aux métadonnées externes qui associent les deux et laisse chacun libre de compréhension de l’autre. Qu’est-ce que j’ai gagné? Ce n’est pas comme si les métadonnées du code source fournissaient une conformité de type ou de mappage. Tout outil de vérification capable d’parsingr les annotations JPA pourrait également parsingr les fichiers de mise en veille prolongée. Les annotations n’ont pas aidé.

Lors d’un contrat, j’avais créé un module Maven avec un package d’implémentations d’interfaces à partir d’un package existant. Il est regrettable que ce nouveau paquet soit l’un des nombreux répertoires d’une construction monolithique; Je l’ai vu comme quelque chose de séparé de l’autre code. Néanmoins, l’équipe utilisait l’parsing des chemins de classes, donc je devais utiliser des annotations pour twigr mon composant sur le système. Ici je ne désirais pas de configuration centralisée; Je voulais simplement une configuration externe. La configuration XML n’était pas parfaite car elle confondait le câblage des dépendances avec l’instanciation des composants. Étant donné que Rod Johnson ne croyait pas au développement basé sur les composants, c’était juste. Néanmoins, j’ai ressenti une fois de plus que les annotations ne m’ont pas aidé.

Comparons cela à quelque chose qui ne me dérange pas: les tests TestNG et JUnit. J’utilise les annotations ici car j’écris ce test en sachant que j’utilise TestNG ou JUnit. Si je remplace l’un pour l’autre, je comprends que je devrai effectuer une transition coûteuse qui s’écartera de la réécriture des tests.

Pour quelque raison que ce soit, j’accepte que TestNG, JUnit, QUnit, unittest et NUnit possèdent mes classes de test. JPA ou Hibernate ne sont en aucun cas propriétaires des classes de domaine associées à des tables. Spring n’est en aucun cas propriétaire de mes services. Je contrôle mon emballage logique et physique afin d’isoler les unités qui en dépendent. Je veux m’assurer que l’éloignement de l’un ne me laisse pas handicapé à cause de toutes les dépendances qu’il a laissées. Dire au revoir est toujours plus facile que de partir. À un certain moment, partir est nécessaire.