Cet article explore notre décision de nous éloigner de l'architecture réactive dans notre projet logiciel. Nous approfondirons les principes fondamentaux des systèmes réactifs, les avantages des E/S non bloquantes et les défis auxquels nous sommes confrontés avec une approche réactive.
Reactive englobe un ensemble de principes et de lignes directrices visant à construire des systèmes et des applications distribués réactifs, caractérisés par :
L'un des principaux avantages des systèmes réactifs est leur utilisation d'E/S non bloquantes. Cette approche évite de bloquer les threads lors des opérations d'E/S, permettant à un seul thread de gérer plusieurs requêtes simultanément. Cela peut améliorer considérablement l'efficacité du système par rapport au blocage traditionnel des E/S.
Dans le multithreading traditionnel, les opérations de blocage posent des défis importants dans l'optimisation des systèmes (Figure 1). Les applications gourmandes consommant trop de mémoire sont inefficaces et pénalisent les autres applications, nécessitant souvent des demandes de ressources supplémentaires comme de la mémoire, du processeur ou des machines virtuelles plus volumineuses.
Figure 1 – Multi-threading traditionnel
Les opérations d'E/S font partie intégrante des systèmes modernes, et leur gestion efficace est primordiale pour éviter les comportements gourmands. Les systèmes réactifs utilisent des E/S non bloquantes, permettant à un faible nombre de threads du système d'exploitation de gérer de nombreuses opérations d'E/S simultanées.
Bien que les E/S non bloquantes offrent des avantages substantiels, elles introduisent un nouveau modèle d'exécution distinct des frameworks traditionnels. Une programmation réactive a émergé pour résoudre ce problème, car elle atténue l'inefficacité des threads de plate-forme inactifs pendant les opérations de blocage (Figure 2).
Figure 2 – Boucle d'événement réactif
Quarkus exploite un moteur réactif alimenté par Eclipse Vert.x et Netty, facilitant les interactions E/S non bloquantes. Mutiny, l'approche privilégiée pour écrire du code réactif avec Quarkus, adopte un paradigme événementiel, dans lequel les réactions sont déclenchées par les événements reçus.
Mutiny propose deux types événementiels et paresseux :
Bien que les systèmes réactifs offrent des avantages, nous avons rencontré plusieurs défis lors du développement :
"En effet, le rapport entre le temps passé à lire et à écrire est bien supérieur à 10 pour 1. Nous lisons constamment du vieux code dans le cadre de l'effort d'écrire du nouveau code. ...[Par conséquent,] le rendre facile à lire rend la lecture plus facile. c'est plus facile d'écrire."
― Robert C. Martin, Clean Code : Un manuel d'artisanat logiciel agile
Voici un exemple de code réactif utilisant Mutiny pour illustrer la complexité :
Multi.createFrom().ticks().every(Duration.ofSeconds(15)) .onItem().invoke(() - > Multi.createFrom().iterable(configs()) .onItem().transform(configuration - > { try { return Tuple2.of(openAPIConfiguration, RestClientBuilder.newBuilder() .baseUrl(new URL(configuration.url())) .build(MyReactiveRestClient.class) .getAPIResponse()); } catch (MalformedURLException e) { log.error("Unable to create url"); } return null; }).collect().asList().toMulti().onItem().transformToMultiAndConcatenate(tuples - > { AtomicInteger callbackCount = new AtomicInteger(); return Multi.createFrom().emitter(emitter - > Multi.createFrom().iterable(tuples) .subscribe().with(tuple - > tuple.getItem2().subscribe().with(response - > { emitter.emit(callbackCount.incrementAndGet()); if (callbackCount.get() == tuples.size()) { emitter.complete(); } }) )); }).subscribe().with(s - > {}, Throwable::printStackTrace, () - > doSomethingUponComplete())) .subscribe().with(aLong - > log.info("Tic Tac with iteration: " + aLong));
Le projet Loom, un développement récent de l'écosystème Java, promet d'atténuer les problèmes associés au blocage des opérations. En permettant la création de milliers de threads virtuels sans modifications matérielles, Project Loom pourrait potentiellement éliminer le besoin d'une approche réactive dans de nombreux cas.
"Le projet Loom va tuer la programmation réactive"
―Brian Goetz
En conclusion, notre décision de s'éloigner du style d'architecture réactive pour adopter une approche pragmatique de la maintenabilité à long terme de notre projet. Bien que les systèmes réactifs offrent des avantages potentiels, les défis qu'ils ont présentés à notre équipe l'emportaient sur ces avantages dans notre contexte spécifique.
Il est important de noter que ce changement n'a pas compromis les performances. Il s'agit d'un résultat positif, car il démontre qu'une architecture non réactive (impérative) bien conçue peut fournir les performances nécessaires sans la complexité associée à l'architecture réactive dans notre cas.
Alors que nous regardons vers l'avenir, l'accent reste mis sur la création d'une base de code non seulement fonctionnelle, mais également facile à comprendre et à maintenir pour les développeurs de tous niveaux d'expérience. Cela réduit non seulement le temps de développement, mais favorise également une meilleure collaboration et un meilleur partage des connaissances au sein de l'équipe.
Dans le graphique ci-dessous, l'axe X représente la complexité croissante de notre base de code à mesure qu'elle évolue, tandis que l'axe Y représente le temps requis pour ces changements de développement.
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!