#Avis d'expert

SAP UI5 et performance – Les bonnes pratiques simple et efficaces

17 minutes

Des techniques simples et rapides peuvent considérablement améliorer les performances des applications.

Pour beaucoup (trop) de monde, la gestion de la performance dans les applications FIORI/SAP UI5 est un domaine complexe où il faut investir beaucoup de temps en trace de performance, optimisation de code, et tout ça pour quelques millisecondes.

À ces personnes, je répondrais qu’il existe une multitude de techniques et concept très simple et rapide à mettre en œuvre permettant d’accroitre drastiquement la performance des applications. Pour certains points, il s’agit même d’actions uniques pour l’ensemble du paysage applicatif.

Il est vrai que l’optimisation de performance peut prendre du temps tant en analyse qu’en actions correctives, mais il s’agit là d’actions ciblées et qui souvent le plus souvent la conséquence d’une mauvaise conception ou encore d’un mauvais développement.

Le choix des technologies et des outils influe également sur la performance globale de vos applications, car avec l’évolution de ceux-ci de nouvelles optimisations voient le jour. On pourrait par exemple comparer les vues CDS et le code ABAP pur. Dans la majeure partie des cas, les vues CDS permettent d’avoir de meilleurs résultats (si elles sont bien faites). De même, l’usage de Framework tel que BOPF vous permet d’offrir des fonctionnalités de manière simple, efficace et performante. Dans ces outils, vos développements auraient probablement des résultats moins probants.

Générer le Component‍-‍preload

Le component-preload est un réel booster de performance, malgré cela, je vois encore beaucoup de projet qui n’en ont pas et c’est bien dommage. En effet, dès lors que l’on utilise les bons outils, ce fichier est automatiquement généré, aussi il n’y a vraiment pas d’effort complémentaire à l’intégrer.

Ce fichier permet de recharger l’ensemble des ressources statiques de votre projet de manière minifier. Ainsi, en une seule requête au serveur, l’ensemble de vos ressources pourront être chargées ce qui réduira considérablement le temps de chargement initial.

Par défaut, le Framework va chercher ce fichier, et s’il ne le trouve pas, il se rabattra sur le fichier Component.js classique. Dans ce dernier cas, au gré des instructions dans votre code source, des dépendances, etc., des fichiers seront demandés nécessitant chaque fois une requête au serveur.

 

// screenshot avec et sans component-preload => Nb requete, poids, temps

 

Selon l’outil de développement que vous utilisez, ce fichier peut être généré manuellement via un module node.js par exemple ou automatiquement via une tache de build de SAP Web IDE par exemple. La gestion de ce fichier est même parfois totalement invisible pour le développeur, car générée lors du déploiement sur le serveur ABAP, mais non visible dans SAP Web IDE. C’est le cas avec la version locale de l’outil par exemple.

Avec la version cloud (full stack), bien qu’une tâche de build soit prévue par les Templates d’applications, vous pouvez agir dessus et modifier son fonctionnement. Par exemple, vous pouvez inclure la génération de la jsdoc dans cette tâche de build en plus de la création du component-preload. Vous pouvez également spécifier les fichiers à inclure ou exclure de cette minification.

// Screen config grunt.js

// SCreen component preload global + component preload sans dossier test par exemple

Optimiser les préchargements

Dans une application FIORI ou SAP UI5, la définition des contrôles que vous utilisez doit être téléchargée depuis le serveur (ou CDN). En effet, pour des raisons évidentes de performance, l’ensemble du Framework n’est pas téléchargé au démarrage, en général, seul le cœur du Framework l’est. Selon que vous consommiez votre application depuis un Launchpad ou en Standalone, vous aurez ou non le choix de modifier le Bootstrap.

Afin d’optimiser les téléchargements de ces contrôles, il convient d’une part de regrouper les appels et d’autre part d’effectuer ces appels de façon asynchrone. L’idée étant de mettre à disposition de l’utilisateur les contrôles nécessaires à l’application le plus tôt possible sans pour autant le faire attendre.

Il est donc préférable de charger non pas un contrôle, mais une librairie contenant ce contrôle. Ensuite, il faut effectuer cet appel au démarrage de l’application et en asynchrone permettant de commencer au plus tôt cette action et de laisser l’utilisateur découvrir tout ce qui peut l’être avec les contenus déjà chargés. L’idée étant qu’au moment où il aura besoin d’un contrôle, dans une vue secondaire par exemple, celui-ci soit déjà chargé, car initié au démarrage.

Pour se faire, il suffit de spécifier dans le manifest les librairies à charger. Attention toutefois, il ne s’agit pas de déclarer l’ensemble des librairies associées aux contrôles utilisés dans l’application. Si vous faites cela, vous risquez finalement de nuire aux performances. En effet, certaines librairies sont plus lourdes que les autres et si vous n’utilisez qu’un seul contrôle de cette librairie, le jeu n’en vaudra peut-être pas la chandelle.

Par ailleurs, certaines librairies ont des dépendances et cela peut également influer dans votre décision d’inclure ou non une librairie.

Il est également possible de demander le chargement du metadata de l’ODataModel de votre application au plus tôt via le paramètre preload.

Je recommande toutefois de déclarer au travers du manifest, l’ensemble des librairies utilisées dans l’application, mais en ne pré chargeant que celles qui présenteront un avantage coté performance.

Rappelons que nous parlons ici de performance au démarrage principalement et que de mauvais choix à ce niveau pourraient mettre vos utilisateurs face une page blanche pendant un certain temps, ce qui nuirait à l’image de l’application.

Passer à l’asynchrone

Dans le même esprit, il est possible de charger de manière asynchrone d’autres ressources. En premier lieu, les sources du Framework lorsque vous consommez une application en Standalone. Pour ce faire, l’attribut sap-data-ui-preload avec la valeur async doit être utilisé au niveau du Bootstrap. Il est à noter que pour des versions plus anciennes, la méthode sera un peu différente.

Ensuite, il convient de ne charger votre composant UI5 qu’à partir du moment où les sources seront chargées. Vous pouvez utiliser l’instruction suivante :

<div data-sap-ui-component data-name=« cod.demo.comp » data-id=« container » data-settings=‘{« id »: « votreId »}’></div>

 

Vous pouvez également faire de même avec une instruction JavaScript (AttachInit), mais la méthode HTML est celle recommandée à ce jour.

Par ailleurs, une stratégie de chargement initiale de données en asynchrone peut également être mise en place. Il ne s’agit donc plus de ressources statiques, mais de données provenant du serveur. Ceci permettant d’initier une configuration de l’application par exemple, ou encore de récupérer un certain nombre de paramètres dynamique utile au bon dérouler de l’application.

Il est également possible et recommandé de charger de manière asynchrone les vues de votre application. Vous pouvez le faire depuis le manifest avec le paramètre async. Ceci n’a d’effet que pour les vues qui ne seraient pas préchargées via le component preload.

Je vous encourage à lire cet article pour prendre connaissance des bonnes pratiques liées au chargement asynchrone de ressources :

https://blogs.sap.com/2018/12/18/ui5ers-buzz-41-best-practices-for-async-loading-in-ui5/

Supprimer les dépendances inutiles

Cela peut paraitre simpliste, mais il convient de ne charger que ce dont on a besoin pour l’application. Malheureusement, je trouve souvent lors d’audit des dépendances inutiles qui nuisent à la performance de l’application. En effet, elles conduisent à télécharger des ressources (et leurs dépendances) inutilement. S’agissant de dépendances, elles ne sont pas toujours incluses dans une librairie préchargée et c’est donc un frein à l’accès à une page de l’application.

Il existe différents outils qui peuvent vous permettre de partir à la chasse à ces dépendances non souhaitées et honnêtement, il n’y en a pas un à privilégier. L’important, c’est de s’assurer de repérer ces cas qui s’apparentent à du code mort.

Optimiser l’usage des requêtes count

La gestion du count est souvent passée sous silence, tant coté Frontend que Backend. C’est à mon sens une erreur, car cela peut vraiment alourdir les temps de traitement.

Il existe plusieurs façons de gérer le count OData et il convient d’utiliser la meilleure option pour votre application. Selon vos besoins, un mode sera plus performant que l’autre. L’important étant également d’être aligné entre le développement UI5 et ABAP.

Souvent, le count n’est tout simplement pas géré, comprenez ici qu’il s’agira du fonctionnement par défaut, soit un appel count pour chaque appel READ de type Query. Si l’on couple cela à une absence de gestion côté ABAP (rappelons que là encore, SAP prévoit un comportement par défaut). Alors vous aurez pour effet d’appeler deux fois votre requête de lecture… pour rien.

Le mode de gestion du count doit être maitrisé et aligné entre le Frontend et le Backend. Côté Frontend, il suffit d’indiquer le mode souhaité au niveau de votre modèle OData, et côté Backend, il faut traiter le cas particulier de réception d’une requête de ce type et appliquer le traitement adéquat.

Exploiter les requêtes Batch

Le batch est une forme d’enveloppe pour vos requetés HTTP. Ce concept présente non seulement des avantages en matière de performance, mais également au niveau de la sécurité. En effet, avec le batch, votre requête étant encapsulée, elle sera protégée par le HTTPS. Rappelons qu’avec HTTPS, seul le contenu de la requête est protégé, et le fait d’encapsulé vos requetés dans une enveloppe dont $batch apportera plus de sécurité.

Coté performance, le simple fait de regrouper plusieurs requêtes en une seule amélioration la performance puisqu’on interrogera le serveur qu’une seule fois. Dans une requête, plusieurs paramètres entrent en ligne de compte dont le temps d’accès au serveur.

Pour gérer l’usage du batch, le paramètre de l’OData Model useBatch est disponible. Lorsqu’il est actif, le Framework groupera certaines opérations qui fonctionnent ensemble comme le count et les appels de type Query. Vous aurez également la main sur le batch d’un point de vue développement afin de retarder l’exécution de cette requête, de gérer plusieurs groupes de requetés, etc. Un ensemble de méthodes sont disponibles vous permettant de gérer très finement l’usage de ce type de requête.

Optimiser l’usage des formulaires de saisie

Une règle d’or dans le développement Web est la suivante : « Never trust the client » ce qui signifie qu’il ne faut pas se contenter de règles ou de contrôles côté client, car ils peuvent facilement être détournés. Ces contrôles doivent donc être repris côté serveur par sécurité.

Toutefois, cela ne signifie pas qu’il faut abandonner l’idée de contrôler un formulaire côté client, car cela présente tout de même certains avantages. D’une part d’un point de vue expérience, mais aussi d’un point de vue performance.

Coté expérience utilisateur, car il est tout de même plus aisé d’accompagner un utilisateur en spécifiant des masques de saisie ou des messages d’erreur directement dans le formulaire avec des codes couleurs, etc.

Par ailleurs, la soumission d’un formulaire se faisant en fin de processus, cela retarde d’autant l’alerte liée à l’erreur de saisie.

Ensuite, au niveau performance, car envoyer une requête au serveur prend du temps et il en est de même pour le contrôle des données côté serveur.

Il est donc préférable de garder la partie masque de saisie, contrôle de formulaire ou encore aides à la saisie côté client tout en gardant à l’esprit que les données devront tout de même être recontrôlées côté serveur.

Assurer la cohérence des librairies

SAP UI5 est un Framework construit sur une base de librairie. Ceci signifie que chaque contrôle fait partie d’une sorte de famille appelée librairie. On retrouve parmi les plus connues, sap.m, sap.uxap, sap.ui.table, etc.

Chaque librairie a des caractéristiques particulières, dont l’aspect responsif. Par exemple, sap.m est responsif quand sap.ui.common ne l’est pas. Il convient donc de choisir ses contrôles en prenant garde à ces caractéristiques.

Certains justifient ces mauvais choix par le fait qu’ils développent des applications pour PC avec grand écran et que dans ce contexte, l’aspect responsif n’importe pas. Je répondrai que c’est une erreur d’appréciation puisqu’il considère dans leur justification seulement la situation de départ et non pas les possibles évolutions dans l’usage. D’autre part, ils négligent le point de la performance. En effet, les deux librairies que j’ai citées fournissent certains contrôles communs comme les labels ou les textes bien que les propriétés puissent différer. Utiliser des contrôles de ces deux librairies aura pour effet de consommer ces deux librairies et donc de les charger en même temps. S’agissant de librairies assez basiques, elles contiennent beaucoup de contenus et sont donc assez lourdes à charger. L’application sera donc ralentie pour cette simple négligence.

Activer le Cache Buster

Le Cache Buster est un mécanisme lié à la gestion du cache qui permet au Framework SAP UI5 de notifier le navigateur d’une nouvelle version disponible pour une ressource. Ainsi, tant que l’index d’une application au sein du Cache Buster n’est pas modifié, les ressources sont chargées depuis ce cache. Dès lors qu’une modification de contenu intervient et que le Cache Buster de l’application concerné est mis à jour, alors le navigateur pourra télécharger la nouvelle version de la ressource.

Ceci permet de simplifier la gestion du cache en centralisant celui-ci dans le cache Buster. Il s’agit d’apposer un index dans les URI des ressources des applications. L’URI sera donc consommée depuis le cache tant que l’index ne change pas. Une fois l’index (ou Timestamp) modifié, via le programme /UI5/APP_INDEX_CALCULATE, qu’il convient d’exécuter régulièrement, la ressource aura une nouvelle URI inconnue du navigateur qui de fait la téléchargera.

Petite astuce, avec le complément d’URL /do-update-meta-data, vous pouvez demander un rafraichissement de l’application que vous consultez (un peu plus difficile lorsque vous exécutez votre application depuis le Launchpad).

Maintenir des librairies d’entreprise

Vous savez que les contrôles UI5 s’inscrivent dans une librairie, mais savez-vous que vous pouvez créer vous-même vos propres librairies ? Ceci présente une multitude d’avantages à commencer par l’industrialisation/la réutilisation de votre code. Côté performance, cela présente également des avantages, car une fois chargée, une librairie reste en cache. Aussi, dès lors que votre librairie est utilisée par plus d’une application pour un même utilisateur, vous commencez à gagner en performance puisque les ressources qu’elle contient auront été chargées une fois pour l’ensemble des applications l’utilisant.

Parmi les ressources que l’on a l’habitude de mettre en librairie, on retrouve bien sûr des contrôles spécifiques, mais aussi des fichiers de fonctions utilitaires, des formateurs ou encore des ressources multimédias par exemple.

Chez Codilog, nous avons l’habitude de construire des solutions qui intègrent plusieurs applications. Une librairie permet de partager des contenus entre ces applications, mais vous pouvez également mettre en œuvre au niveau de l’entreprise ce genre d’initiative. Attention toutefois à ne pas tout mettre dans une seule et même librairie au risque de l’alourdir et d’en perdre les avantages de performance.

Publier correctement les tuiles

Il existe différentes manières de publier une application dans le Launchpad mais l’ensemble de ces méthodes reposes sur 2 « outils » : La transaction LPD_CUST et le Launchpad Designer.

En effet, le Launchpad designer permet de définir les groupes et catalogues de tuiles avec en particulier la définition du Target Mapping. Cette étape permet de cibler l’application qui sera exécutée lors du clic sur la tuile.

Pour configurer ce Target Mapping, vous aurez 2 options :

Référencer le paramétrage réalisé dans la transaction LPD_CUST ou saisir des informations de l’application (son namespace et son chemin ICF principalement).

Je vous recommande de choisir la 2eme méthode qui permet de faire moins d’erreur, surtout si vous ne maitrisez pas bien votre sujet. En effet, j’ai de très nombreuses fois constaté des erreurs de configuration qui bien que paraissant anodines ont de forte répercussions sur les performances.

En effet, il est possible de publier 1 application et de l’exécuter en dehors du Launchpad, comme si elle était exécutée en standalone. Ceci a pour effet de télécharger l’ensemble des ressources nécessaire comme le thème graphique et les librairies de contrôles.

Si vous exécuter votre application « normalement » au travers du Launchpad, alors ces ressources risque fort d’être déjà disponibles. Ainsi vous pourrez éviter de perdre PLUSIEURS secondes au démarrage de votre application.

Attention toutefois aux faux semblant car une mauvaise publication vous donnera certes l’impression d’une exécution dans le Launchpad puisque vos écrans y seront intégrés mais l’exécution se fera belle et bien en dehors.

D’une manière générale, outre vos requêtes OData au démarrage, votre application ne devrait pas excéder 3 secondes de chargement initial. En cas de besoin, n’hésitez pas à nous contacter pour vous aider à cibler vos problèmes de performance.

Vous trouverez plus d’informations sur le site d’aide SAP officiel :

https://help.sap.com/viewer/825270ffffe74d9f988a0f0066ad59f0/CF/en-US/ec4fda32e66f49d880a8fc6ad54a993c.html