Le livre «Learning Java EE. Programmation moderne pour les grandes entreprises "

image Salut Habr!

Ce livre décrit la nouvelle génération de Java EE. Vous embarquerez pour un voyage à travers Java EE dans le contexte du monde moderne des microservices et conteneurs. Il ne s'agit pas d'un guide de référence sur la syntaxe de l'API - les concepts et techniques présentés ici reflètent l'expérience réelle d'une personne qui a récemment parcouru ce chemin, en accordant une attention particulière aux obstacles qui se posent et est prête à partager ses connaissances. Dans une variété de situations, de la création d'un package pour les tests et l'utilisation du cloud, ce livre sera un compagnon idéal pour les débutants et les développeurs expérimentés cherchant à comprendre plus qu'une simple API, et les aidera à reconstruire leur réflexion pour créer une architecture d'application moderne en Java EE .

Séquence d'exécution


Les processus métier mis en œuvre dans les applications d'entreprise décrivent des flux de processus spécifiques. Pour les scénarios d'entreprise impliqués, il s'agit soit d'un processus de demande et de réponse synchrone, soit d'un traitement asynchrone d'un processus initié.

Les scénarios d'entreprise sont appelés dans des threads séparés, un thread par demande ou appel. Les flux sont créés par le conteneur et placés dans le lecteur pour être réutilisés une fois l'appel correctement traité. Par défaut, les processus métier définis dans les classes d'application, ainsi que les tâches transversales telles que les transactions, sont exécutés séquentiellement.

Exécution synchrone


Un scénario typique lorsqu'une demande HTTP nécessite une réponse de la base de données est implémenté comme suit. Un thread traite la requête arrivant à la boucle, par exemple, le JAX-RS UsersResource, en inversant le principe de contrôle; La méthode de ressource JAX-RS est appelée par le conteneur. La ressource implémente et utilise l'EJB UserManagement, qui est également implicitement appelé par le conteneur. Toutes les opérations sont effectuées par des intermédiaires de manière synchrone. L'utilisateur EJB utilisera le gestionnaire d'entités pour stocker la nouvelle entité et dès que la méthode métier qui a initié la transaction actuellement active se termine, le conteneur tentera de valider la transaction dans la base de données. En fonction du résultat de la transaction, la méthode de ressource du circuit reprend son fonctionnement et génère une réponse au client. Tout se passe de manière synchrone, à ce moment le client est bloqué et attend une réponse.

L'exécution synchrone comprend le traitement des événements CDI synchrones. Ils séparent le déclenchement des événements de domaine de leur traitement, cependant, les événements sont traités de manière synchrone. Il existe plusieurs méthodes pour surveiller les transactions. Si une étape de transaction est indiquée, l'événement peut être traité à ce stade - pendant la fixation de la transaction, avant son achèvement, après l'achèvement, en cas de transaction infructueuse ou réussie. Par défaut, ou si la transaction est inactive, les événements CDI sont traités immédiatement lorsqu'ils se produisent. Cela permet aux ingénieurs d'implémenter des solutions complexes - par exemple, en utilisant des événements qui ne se produisent qu'après l'ajout réussi d'entités à la base de données. Quoi qu'il en soit, dans tous les cas, le traitement est effectué de manière synchrone.

Exécution asynchrone


L'exécution synchronisée des tâches répond aux exigences de nombreux scénarios d'entreprise, mais il y a des moments où vous avez besoin d'un comportement asynchrone. Il existe un certain nombre de restrictions sur l'utilisation des threads par l'environnement Java EE. Le conteneur gère les ressources et les flux et les place dans le lecteur. Les utilitaires de contrôle d'accès concurrentiels externes sont situés à l'extérieur du conteneur et ne connaissent pas ces flux. Par conséquent, le code d'application ne doit pas s'exécuter et contrôler ses threads. Pour ce faire, il utilise les fonctionnalités Java EE. Il existe plusieurs API avec prise en charge asynchrone intégrée.

Méthodes EJB asynchrones

La manière la plus simple d'implémenter un comportement asynchrone consiste à utiliser l'annotation @Asynchronous pour une méthode métier de classe EJB ou EJB. Les appels à ces méthodes reviennent immédiatement, parfois avec une réponse de type Future. Ils s'exécutent dans un thread séparé contrôlé par le conteneur. Cette méthode fonctionne bien pour des scénarios simples, mais est limitée aux EJB:

@Asynchronous @Stateless public class Calculator { public void calculatePi(long decimalPlaces) { //      } } 

Service de gestion des performances

Pour l'exécution asynchrone de tâches dans des objets CDI gérés ou à l'aide des utilitaires de contrôle de concurrence Java SE, Java EE inclut des versions gérées par conteneur des fonctions ExecutorService et ScheduledExecutorService. Ils sont utilisés pour implémenter des tâches asynchrones dans les threads pilotés par conteneur. Les instances ManagedExecutorService et ManagedScheduledExecutorService sont incorporées dans le code d'application. Ils peuvent être utilisés pour exécuter leur propre logique, mais sont plus efficaces lorsqu'ils sont combinés avec des utilitaires de contrôle de concurrence Java SE, tels que des valeurs futures complémentaires. L'exemple suivant montre comment créer des valeurs futures remplies à l'aide de threads pilotés par conteneur:

 import javax.annotation.Resource; import javax.enterprise.concurrent.ManagedExecutorService; import java.util.Random; import java.util.concurrent.CompletableFuture; @Stateless public class Calculator { @Resource ManagedExecutorService mes; public CompletableFuture<Double> calculateRandomPi(int maxDecimalPlaces) { return CompletableFuture.supplyAsync(() -> new Random().nextInt(maxDecimalPlaces) + 1, mes) .thenApply(this::calculatePi); } private double calculatePi(long decimalPlaces) { … } } 

L'objet Calculatrice renvoie la valeur future complétée du type double, qui peut toujours être calculée lorsque le contexte appelant reprend. Il peut être demandé lorsque les calculs sont terminés, ainsi que combiné avec les calculs ultérieurs. Peu importe où de nouveaux threads sont requis dans l'application d'entreprise, vous devez utiliser la fonctionnalité Java EE pour les gérer.

Événements CDI asynchrones

Les événements CDI peuvent également être traités de manière asynchrone. Dans ce cas, le conteneur fournit également un flux pour gérer les événements. Pour décrire un gestionnaire d'événements asynchrone, la méthode est annotée avec @ObservesAsync et l'événement est activé à l'aide de la méthode fireAsync (). Les extraits de code suivants illustrent les événements CDI asynchrones:

 @Stateless public class CarManufacturer { @Inject CarFactory carFactory; @Inject Event<CarCreated> carCreated; public Car manufactureCar(Specification spec) { Car car = carFactory.createCar(spec); carCreated.fireAsync(new CarCreated(spec)); return car; } } 

Le gestionnaire d'événements est appelé dans son propre thread géré par conteneur:

 import javax.enterprise.event.ObservesAsync; public class CreatedCarListener { public void onCarCreated(@ObservesAsync CarCreated event) { //    } } 

Pour des raisons de compatibilité descendante, les événements CDI synchrones peuvent également être traités dans la méthode EJB asynchrone. Ainsi, les événements et les gestionnaires sont définis comme synchrones, et la méthode du gestionnaire est une méthode métier EJB avec annotation @Asynchronous. Avant l'introduction des événements asynchrones dans la norme CDI pour Java EE 8, c'était le seul moyen d'implémenter cette fonctionnalité. Pour éviter toute confusion dans Java EE 8 et versions ultérieures, il est préférable d'éviter cette implémentation.

Étendues de traitement asynchrones

Étant donné que le conteneur ne contient pas d'informations sur la durée des tâches asynchrones, l'utilisation des étendues dans ce cas est limitée. Les objets ayant une portée dans la demande ou la session qui étaient disponibles lorsque la tâche asynchrone a été lancée ne seront pas nécessairement actifs tout au long de son implémentation - la demande et la session peuvent se terminer bien avant son achèvement. Ainsi, les threads effectuant des tâches asynchrones, telles que celles fournies par le service d'exécuteur programmé ou les événements asynchrones, peuvent ne pas avoir accès aux instances d'objets gérés avec portée dans la demande ou la session qui étaient actives pendant l'appel. Il en va de même pour l'accès aux liens vers des instances intégrées, par exemple dans les méthodes lambda qui font partie d'une exécution synchrone.

Ceci doit être pris en compte lors de la modélisation des tâches asynchrones. Toutes les informations sur un appel particulier doivent être fournies au début de la tâche. Cependant, une tâche asynchrone peut avoir ses propres instances d'objets gérés avec une portée limitée.

Définir l'exécution du temps

Les scénarios d'entreprise peuvent être appelés non seulement de l'extérieur, par exemple via une requête HTTP, mais également à partir de l'application - une tâche qui s'exécute à un moment précis.

Dans le monde Unix, la fonctionnalité d'exécution de travaux périodiques est populaire - ce sont les tâches du planificateur. Les EJB offrent des capacités similaires à l'aide de minuteries EJB. Les temporisateurs invoquent des méthodes métier à des intervalles spécifiés ou après une heure spécifiée. L'exemple suivant décrit une minuterie cyclique qui démarre toutes les dix minutes:

 import javax.ejb.Schedule; import javax.ejb.Startup; @Singleton @Startup public class PeriodicJob { @Schedule(minute = "*/10", hour = "*", persistent = false) public void executeJob() { //   10  } } 

Tous les EJB - singletones, objets gérés avec ou sans persistance d'état - peuvent créer des temporisations. Cependant, dans la plupart des scénarios, il est logique de créer des temporisateurs pour singleton uniquement. Le délai est défini pour tous les objets actifs. Habituellement, il est nécessaire de lancer les tâches planifiées à temps, c'est pourquoi il est utilisé dans singleton. Pour la même raison, dans cet exemple, l'objet EJB doit être actif au démarrage de l'application. Cela garantit que la minuterie commence à fonctionner immédiatement.

Si vous décrivez le temporisateur comme une constante, sa durée de vie s'étend à l'ensemble du cycle de vie de la machine virtuelle Java. Le conteneur est responsable du stockage des temporisateurs persistants, généralement dans la base de données. Les minuteries permanentes, qui devraient fonctionner lorsque l'application n'est pas disponible, s'activent au démarrage. Il vous permet également d'utiliser les mêmes minuteries avec plusieurs instances de l'objet. Des minuteries constantes avec une configuration de serveur appropriée sont une solution appropriée si vous devez exécuter un processus métier exactement une fois sur plusieurs serveurs.

Les temporisateurs créés automatiquement à l'aide de l'annotation Schedule sont décrits à l'aide d'expressions cron de type Unix. Pour plus de flexibilité, les temporisateurs EJB sont décrits par programme à l'aide du service de temporisation fourni par le conteneur, qui crée les méthodes de rappel Timers et Timeout .

Les tâches périodiques et différées peuvent également être décrites en dehors des EJB à l'aide du service de planificateur géré par conteneur. Une instance de ManagedScheduledExecutorService qui exécute des tâches après le délai spécifié ou à des intervalles spécifiés est implémentée dans les composants gérés. Ces tâches seront implémentées dans des unités d'exécution pilotées par conteneur:

 @ApplicationScoped public class Periodic { @Resource ManagedScheduledExecutorService mses; public void startAsyncJobs() { mses.schedule(this::execute, 10, TimeUnit.SECONDS); mses.scheduleAtFixedRate(this::execute, 60, 10, TimeUnit.SECONDS); } private void execute() { … } } 

L'appel de la méthode startAsyncJobs () exécutera la fonction execute () sur le thread géré dix secondes après l'appel, puis toutes les dix secondes après la première minute.

Asynchronie et réactivité dans JAX-RS

JAX-RS prend en charge le comportement asynchrone afin de ne pas bloquer inutilement les flux de requêtes côté serveur. Même si une connexion HTTP attend une réponse, le flux de demandes peut continuer à traiter d'autres demandes pendant qu'un long processus s'exécute sur le serveur. Les flux de demandes sont agrégés dans un conteneur, et ce référentiel de demandes a une certaine taille. Afin de ne pas gaspiller le flux de demandes, les méthodes de ressources asynchrones JAX-RS créent des tâches qui sont exécutées lorsque le flux de demandes revient et peuvent être réutilisées. La connexion HTTP reprend et donne une réponse après la fin de la tâche asynchrone ou après un délai d'expiration. L'exemple suivant montre la méthode de ressource asynchrone JAX-RS:

 @Path("users") @Consumes(MediaType.APPLICATION_JSON) public class UsersResource { @Resource ManagedExecutorService mes; … @POST public CompletionStage<Response> createUserAsync(User user) { return CompletableFuture.supplyAsync(() -> createUser(user), mes); } private Response createUser(User user) { userStore.create(user); return Response.accepted().build(); } } 

Pour garder le flux de demandes occupé trop longtemps, la méthode JAX-RS doit se terminer rapidement. Cela est dû au fait que la méthode des ressources est appelée à partir du conteneur au moyen d'une inversion de contrôle. Le résultat obtenu à l'étape d'achèvement sera utilisé pour reprendre la connexion client à la fin du traitement.

Le retour des étapes d'achèvement est une technologie relativement nouvelle dans l'API JAX-RS. Si vous devez décrire le retard et en même temps offrir une plus grande flexibilité avec une réponse asynchrone, vous pouvez inclure le type AsyncResponse dans la méthode. Cette approche est illustrée dans l'exemple suivant:

 import javax.ws.rs.container.AsyncResponse; import javax.ws.rs.container.Suspended; @Path("users") @Consumes(MediaType.APPLICATION_JSON) public class UsersResource { @Resource ManagedExecutorService mes; … @POST public void createUserAsync(User user, @Suspended AsyncResponse response) { response.setTimeout(5, TimeUnit.SECONDS); response.setTimeoutHandler(r -> r.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE).build())); mes.execute(() -> response.resume(createUser(user))); } } 

Grâce aux délais d'attente créés, la demande du client n'attendra pas indéfiniment, mais seulement jusqu'à ce que le résultat soit reçu ou que le délai d'appel expire. Cependant, les calculs continueront car ils sont effectués de manière asynchrone. Pour les ressources JAX-RS implémentées en tant qu'EJB, vous pouvez appliquer l'annotation @Asynchronous afin de ne pas appeler explicitement les méthodes métier asynchrones via l'exécuteur de service.

Le client JAX-RS prend également en charge le comportement asynchrone. Selon les besoins, il est judicieux de ne pas le bloquer lors des appels HTTP. L'exemple précédent montre comment définir des délais pour les demandes des clients. Pour les appels système externes de longue durée et en particulier parallèles, il est préférable d'utiliser un comportement asynchrone et réactif.

Considérez plusieurs applications serveur qui fournissent des informations météorologiques. Le composant client accède à toutes ces applications et calcule les prévisions météorologiques moyennes. Idéalement, vous pourriez rendre l'accès aux systèmes parallèle:

 import java.util.stream.Collectors; @ApplicationScoped public class WeatherForecast { private Client client; private List<WebTarget> targets; @Resource ManagedExecutorService mes; @PostConstruct private void initClient() { client = ClientBuilder.newClient(); targets = … } public Forecast getAverageForecast() { return invokeTargetsAsync() .stream() .map(CompletableFuture::join) .reduce(this::calculateAverage) .orElseThrow(() -> new IllegalStateException("   ")); } private List<CompletableFuture<Forecast>> invokeTargetsAsync() { return targets.stream() .map(t -> CompletableFuture.supplyAsync(() -> t .request(MediaType.APPLICATION_JSON_TYPE) .get(Forecast.class), mes)) .collect(Collectors.toList()); } private Forecast calculateAverage(Forecast first, Forecast second) { … } @PreDestroy public void closeClient() { client.close(); } } 

La méthode invokeTargetsAsync () appelle les objets disponibles de manière asynchrone, en invoquant le service d'exécuteur planifié. Les descripteurs CompletableFuture sont renvoyés et utilisés pour calculer les résultats moyens. Le début de la méthode join () sera bloqué jusqu'à la fin de l'appel et la réception des résultats.

Les objets appelés de manière asynchrone démarrent et attendent une réponse de plusieurs ressources à la fois, peut-être plus lentement. Dans ce cas, l'attente des réponses des ressources du service météo prend autant de temps que l'attente de la réponse la plus lente, et pas toutes les réponses ensemble.

La dernière version de JAX-RS a un support intégré pour les étapes d'achèvement, ce qui réduit le code stéréotypé dans les applications. Comme pour les valeurs remplies, l'appel renvoie immédiatement le code de la phase d'achèvement pour référence future. L'exemple suivant montre les fonctions client réactives JAX-RS utilisant l'appel rx ():

 public Forecast getAverageForecast() { return invokeTargetsAsync() .stream() .reduce((l, r) -> l.thenCombine(r, this::calculateAverage)) .map(s -> s.toCompletableFuture().join()) .orElseThrow(() -> new IllegalStateException("   ")); } private List<CompletionStage<Forecast>> invokeTargetsAsync() { return targets.stream() .map(t -> t .request(MediaType.APPLICATION_JSON_TYPE) .rx() .get(Forecast.class)) .collect(Collectors.toList()); } 

Dans l'exemple ci-dessus, vous n'avez pas besoin de rechercher le service des exécuteurs programmés - le client JAX-RS le gérera lui-même. Avant l'apparition de la méthode rx (), les clients utilisaient un appel async () explicite. Cette méthode s'est comportée de la même manière, mais n'a renvoyé que les objets Future. L'utilisation d'une approche réactive chez les clients est optimale pour la plupart des projets.
Comme vous pouvez le voir, Java EE utilise un service d'artiste géré par conteneur.

Concevoir des concepts et des principes dans Java EE moderne


L'API Java EE est basée sur des conventions et des principes de conception énoncés comme des normes. Les ingénieurs logiciels y trouveront des modèles d'API et des approches de développement d'applications familiers. Le but de Java EE est de promouvoir une utilisation cohérente de l'API.

Le principe principal des applications axées principalement sur la mise en œuvre de scénarios commerciaux est le suivant: la technologie ne doit pas interférer. Comme déjà mentionné, les ingénieurs devraient pouvoir se concentrer sur la mise en œuvre de la logique métier sans passer la plupart du temps sur des questions technologiques et d'infrastructure. Idéalement, la logique du domaine est implémentée en Java simple et est complétée par des annotations et d'autres propriétés prises en charge par l'environnement de l'entreprise, sans affecter le code de domaine ni le compliquer. Cela signifie que la technologie ne nécessite pas beaucoup d'attention des ingénieurs et n'impose pas de restrictions trop importantes. L'environnement J2EE nécessitait auparavant de nombreuses solutions très complexes. Pour implémenter les interfaces et étendre les classes de base, nous avons dû utiliser des objets gérés et des objets de stockage persistants. Cela a compliqué la logique du sujet et rendu les tests difficiles.

En Java EE, la logique du domaine est implémentée sous forme de classes Java simples équipées d'annotations, selon lesquelles le conteneur résout certaines tâches de l'entreprise lors de l'exécution de l'application. La pratique de la création de code propre implique souvent l'écriture d'un code plus beau que pratique à réutiliser. Java EE prend en charge cette approche. Si, pour une raison quelconque, vous devez supprimer la technologie et laisser la logique pure du sujet, cela se fait en supprimant simplement les annotations correspondantes.

Comme nous le verrons au chapitre 7, cette approche de programmation implique la nécessité de tests, car pour les programmeurs, la plupart des spécifications Java EE ne sont rien d'autre que des annotations.

Tout au long de l'API, un principe de conception appelé inversion de contrôle (IoC) a été adopté - en d'autres termes, "ne nous appelez pas, nous nous appellerons". Cela est particulièrement visible dans les circuits d'application, tels que les ressources JAX-RS. Les méthodes de ressource sont décrites à l'aide d'annotations de méthode Java, qui sont ensuite appelées par le conteneur dans le contexte approprié. Il en va de même pour l'injection de dépendances, dans laquelle vous devez choisir des générateurs ou prendre en compte des tâches transversales telles que les intercepteurs. Les développeurs d'applications peuvent se concentrer sur l'implémentation de la logique et la description des relations, laissant l'implémentation des détails techniques dans un conteneur. Un autre exemple, moins évident, est la description de la conversion d'objets Java en JSON et vice versa via des annotations JSON-B. Les objets sont transformés non seulement sous une forme explicite et programmée, mais aussi implicitement, dans un style déclaratif.

Un autre principe qui permet aux ingénieurs d'appliquer efficacement cette technologie est la programmation par accord. Par défaut, Java EE définit un comportement spécifique qui correspond à la plupart des scénarios d'utilisation. S'il ne suffit pas ou s'il ne répond pas aux exigences, le comportement peut être redéfini, souvent à plusieurs niveaux.
Il existe de nombreux exemples de programmation de convention. L'un d'eux est l'utilisation de méthodes de ressources JAX-RS qui convertissent la fonctionnalité Java en réponses HTTP. Si le comportement standard de JAX-RS en ce qui concerne les réponses ne satisfait pas aux exigences, vous pouvez appliquer le type de réponse Réponse. Un autre exemple est la spécification d'objets gérés, qui est généralement implémentée à l'aide d'annotations. Pour modifier ce comportement, vous pouvez utiliser le descripteur XML beans.xml. Il est très pratique pour les programmeurs que dans le monde moderne de Java EE, les applications d'entreprise soient développées de manière pragmatique et hautes performances qui ne nécessitent généralement pas une utilisation intensive de XML comme auparavant.

Quant à la productivité des programmeurs, un autre principe important du développement sur Java EE est que cette plate-forme nécessite une intégration dans le conteneur de différents standards. Étant donné que les conteneurs prennent en charge un ensemble spécifique d'API - et si l'intégralité de l'API Java EE est prise en charge, c'est exactement le cas -, il nécessite également des implémentations d'API pour fournir une intégration transparente des autres API. L'avantage de cette approche est la possibilité d'utiliser les ressources JAX-RS de la conversion JSON-B et de la technologie de validation de bean sans configuration explicite supplémentaire, à l'exception des annotations. Dans les exemples précédents, nous avons vu comment les fonctions définies dans les normes individuelles peuvent être utilisées ensemble sans effort supplémentaire. C'est l'un des plus grands avantages de la plate-forme Java EE. Une spécification générique garantit une combinaison de normes individuelles. Les programmeurs peuvent compter sur certaines fonctionnalités et implémentations fournies par le serveur d'applications.

Code de haute qualité facile à utiliser


Les programmeurs conviennent généralement que vous devez vous efforcer d'écrire du code de haute qualité. Cependant, toutes les technologies ne sont pas aussi bien adaptées à cela.

Comme mentionné au début du livre, l'accent sur le développement d'applications devrait être la logique métier. En cas de changement de logique métier ou d'émergence de nouvelles connaissances, il est nécessaire de mettre à jour le modèle de domaine, ainsi que le code source. Une refactorisation itérative est nécessaire pour créer et maintenir un modèle de domaine et un code source de haute qualité dans leur ensemble. Les efforts pour approfondir la compréhension du sujet sont décrits dans le concept de conception orientée problème.

Il existe de nombreuses publications sur le refactoring au niveau du code.Une fois que la logique métier est présentée sous forme de code et vérifiée par des tests, les programmeurs doivent consacrer du temps et faire des efforts pour repenser et améliorer la première option. Cela s'applique aux identificateurs de noms, de méthodes et de classes. Le choix des noms, des niveaux d'abstraction et des points de responsabilité communs est particulièrement important.

Selon la définition de la conception orientée problème, le domaine devrait correspondre autant que possible à sa représentation sous forme de code. Cela inclut, en particulier, la langue du domaine - en d'autres termes, la façon dont les programmeurs et les experts commerciaux parlent de certaines fonctions. L'objectif de toute l'équipe est de trouver un langage commun universel qui sera efficacement utilisé non seulement dans les discussions et sur les diapositives de présentation, mais aussi dans le code. Le perfectionnement des connaissances dans le domaine des affaires se fera de façon cyclique. Comme la refactorisation au niveau du code, cette approche implique que le modèle d'origine ne répondra pas pleinement à toutes les exigences.

Ainsi, la technologie appliquée devrait prendre en charge les modifications de modèle et de code. S'il y a trop de restrictions, il sera difficile d'apporter des modifications plus tard.

Pour le développement d'applications en général, et notamment pour le refactoring, il est impératif que le logiciel soit suffisamment couvert par des tests automatisés. Le code étant en constante évolution, les tests de régression garantissent qu'aucune des fonctions métier n'est accidentellement endommagée. Ainsi, un nombre suffisant de tests de contrôle prend en charge le refactoring, permettant aux ingénieurs de comprendre clairement qu'après avoir apporté des modifications, toutes les fonctionnalités fonctionnent toujours comme prévu. Idéalement, la technologie devrait permettre de tester sans imposer de restrictions sur la structure du code. Nous en discuterons plus en détail au chapitre 7.

Pour permettre le refactoring, une liaison faible est préférable à une liaison étroite. La modification d'un composant affecte toutes les fonctions qui l'appellent explicitement et tous les composants dont il a besoin. Java EE prend en charge plusieurs options de liaison faibles: injection de dépendances, événements et tâches de bout en bout telles que les hooks. Tout cela simplifie les changements de code.

Il existe un certain nombre d'outils et de méthodes pour mesurer la qualité. En particulier, l'analyse de code statique vous permet de collecter des informations sur la complexité, la connectivité, les dépendances entre les classes et les packages, et l'implémentation dans son ensemble. Ces outils aident les ingénieurs à identifier les problèmes potentiels et à créer une vue d'ensemble du projet logiciel. Le chapitre 6 vous montrera comment vérifier automatiquement la qualité du code.

En général, il est recommandé de réorganiser constamment le code et d'améliorer sa qualité. Les projets logiciels sont souvent créés pour introduire de nouvelles fonctions génératrices de revenus et non pour améliorer les fonctionnalités existantes. Le problème est que le refactoring et l'amélioration de la qualité du code à première vue n'apportent pas d'avantages à l'entreprise. Ce n'est bien sûr pas le cas. Afin d'atteindre une vitesse stable et d'intégrer de nouvelles fonctions avec une qualité satisfaisante, il est nécessaire de revoir les fonctions existantes. Idéalement, les boucles de refactorisation doivent être intégrées dans le diagramme de projet. L'expérience montre que les chefs de projet ignorent souvent ce problème. Cependant, une équipe d'ingénieurs logiciels est responsable du maintien de la qualité.

À propos de l'auteur


Sebastian Daschner est un pigiste Java qui travaille comme consultant et enseignant, un passionné de programmation et Java (EE). Il participe à JCP, contribue à la création de nouvelles normes Java EE, sert les groupes d'experts 37SR et 374 dans JSR et travaille dans divers projets open source. Pour sa contribution à la communauté et à l'écosystème Java, il a reçu le titre de champion du développement Java et Oracle.

Sebastian intervient régulièrement lors de conférences internationales sur l'informatique telles que JavaLand, JavaOne et Jfokus. Il a reçu le JavaOne Rockstar Award lors de la conférence JavaOne 2016. Avec le directeur de la communauté Java Steve Chin, il a assisté à des dizaines de conférences Java et de groupes d'utilisateurs tout en voyageant à moto. Steve et Sebastian ont créé JOnsen, une non-conférence Java tenue dans une source thermale dans le Japon rural.

À propos de Reviewer


Melissa McKay est une développeur de logiciels avec 15 ans d'expérience dans la création de différents types d'applications pour les clients privés et les entreprises. Maintenant, elle est principalement engagée dans les applications Java côté serveur qui sont utilisées dans le domaine des communications et de la télévision. Ses intérêts incluent les systèmes de cluster, elle a une passion particulière pour la résolution de problèmes associés aux applications parallèles et multi-thread.

Melissa assiste régulièrement à la non-conférence JCrete en Crète, en Grèce, et a été heureuse d'assister à l'ouverture de la non-conférence JOnsen au Japon. Elle aime participer à des conférences informatiques bénévoles pour les enfants, telles que JavaOne4Kids et JCrete4Kids. Elle était membre du comité de contenu de JavaOne 2017 et est un membre actif du Denver Java User Group.

»Plus d'informations sur le livre sont disponibles sur le site Web de l'éditeur
» Contenu
» Extrait

Habrozhiteley à 20% de réduction sur le coupon - Java EE

Source: https://habr.com/ru/post/fr418025/


All Articles