Skip to content

Latest commit

 

History

History
854 lines (647 loc) · 40.6 KB

vue-architecture-developpement.adoc

File metadata and controls

854 lines (647 loc) · 40.6 KB

Vue développement

Dernière modification : 2024-10-11

Date dernière revue globale : <Faire régulièrement des revues complètes de la vue (au moins une fois par an tant que le projet est actif) et mentionner la date ici>

Statut du document : <Donner ici le statut de la vue, par exemple 'DRAFT', 'FINALISÉ',…​>

1. Introduction

Ceci est la vue développement de l’application. Elle décrit le code à produire et comment l’écrire.

Les autres vues du dossier sont accessibles d’ici.

Le glossaire du projet est disponible ici. Nous ne redéfinirons pas ici les termes fonctionnels ou techniques utilisés.

1.1. Documentation de Référence

Tip
Mentionner ici les documents d’architecture de référence (mutualisés). Ce document ne doit en aucun cas reprendre leur contenu sous peine de devenir rapidement obsolète et inmaintenable.
Table 1. Références documentaires développement
Version Titre/URL du document Détail

1

1.0

https://references.modernisation.gouv.fr/rgaa-accessibilite/#menu

RGAA

2. Non statué

2.1. Points soumis à étude complémentaire

Table 2. Points soumis à étude complémentaire
ID Détail Statut Porteur du sujet Échéance

ED1

Le choix Angular ou React.JS pour le frontend est encore soumis à étude. Ceci n’impacte pas la partie back des services REST

EN_COURS

Equipe méthodes et outils

AVANT 2040

2.2. Hypothèses

Table 3. Hypothèses
ID Détail

HD1

Même si ce point n’est pas encore totalement validé, l’application nécessitera un JRE 9 + pour tirer profil de librairies et frameworks Java indispensables au projet.

3. Contraintes

Tip

Lister ici les contraintes relatives à l’architecture logicielle, ceci inclut par exemple mais pas seulement :

  • L’obligation d’utiliser un framework ou une filière technologique précise

  • Les budgets maximums de licence ou de développement

  • L’outillage (IDE, …)

  • L’intégration continue

  • Les normes et seuils de qualité de code applicables

  • Les tests (taux de couverture, répartition par type de test, …)

Exemple 1 : La couverture de code devra être d’au moins 60%

Exemple 2 : Le module devra se baser sur le framework Hibernate pour la persistance et CDI pour l’injection de dépendance

Exemple 3 : l’application sera construite, testée et déployée en continu à chaque push via la plateforme Gitlab-ci

4. Exigences non fonctionnelles

Tip

Contrairement aux contraintes qui fixaient le cadre auquel toute application devait se conformer, les exigences non fonctionnelles sont données par les porteurs du projet (MOA en général). Prévoir des interviews pour les déterminer. Si certaines exigences ne sont pas réalistes, le mentionner dans le référentiel des points à statuer.

4.1. Accessibilité

Tip

Cette application doit-elle être accessible aux non/mal voyants ? malentendants ?

Si oui, quelle niveau d’accessibilité ? Se référer de préférence au Référentiel Général d’Accessibilité (RGAA) qui préconise un niveau WCAG 2.0 AA :

Il existe d’autres normes d’accessibilité (WCAG, AccessiWeb …) . Attention à correctement évaluer le niveau visé (ni sur-qualité, ni sous-qualité) :

  • Atteindre un niveau d’accessibilité très élevé peut être coûteux et contraignant technologiquement. Il demande également de bonnes compétences (accessibilité, HTML5/CSS3 en particulier) et des profils rares.

  • La loi est de plus en plus stricte pour les administrations qui doivent respecter un niveau d’accessibilité suffisant (loi n°2005-102 du 11 février 2005 pour l’égalité des droits et des chances, la participation et la citoyenneté des personnes handicapées). « Tous les sites publics européens doivent atteindre le double A (AA) du W3C/WAI ».

4.2. Ergonomie

4.2.1. Charte ergonomique

Tip

En général, on se réfère ici à la charte ergonomique de l’organisme. Lister néanmoins d’éventuelles spécificités. Ne pas reprendre les contraintes d’accessibilité listées plus haut.

4.2.2. Spécificités sur les widgets

Tip

Des comportements ergonomiques très précis peuvent impacter assez fortement l’architecture et imposer une librairie de composants graphiques ou une autre. Il est fortement déconseillé de personnaliser des librairies existantes (coût de maintenance très élevé, grande complexité). Bien choisir sa librairie ou restreindre ses besoins.

Exemple 1 : les tableaux devront être triables suivant plusieurs colonnes.

Exemple 2 : de nombreux écrans seront pourvus d’accordéons

4.2.3. Polices de caractère

Tip

Décrire ici les polices de caractère à utiliser pour les pages Web, les applications ou les documents composés.

Le choix des polices suit des contraintes de licences. Afin d’assurer une sécurité juridique au projet, attention aux polices commerciales soumises à royalties (en particulier les polices appartenant à Microsoft comme Times New Roman, Courier, Verdana, Arial) et qui ne permettent pas de produire gratuitement des documents sans passer par leurs éditeurs (Word, …).

Voir par exemple la police Marianne préconisée par le gouvernement en tant que police à chasse variable.

Redhat propose quatre familles de polices Liberation Mono en licence Open Source sécurisante sur un plan juridique et compatible métriquement avec le Monotype, le Courrier New, l’Arial et le Times New Roman.

4.2.4. Site Web adaptatif

Tip

Lister les contraintes d’affichage multi-support. Utiliser quand c’est possible les frameworks modernes (type AngularJS ou React.js). Il existe plusieurs niveaux d’adaptation des pages Web :

  • Statique (largeur de page fixe).

  • Dynamique (redimensionnement automatique, les tailles sont exprimées en %).

  • Adaptatif (les distances sont exprimées en unités dont la taille dépend du support).

  • Responsive (le contenu et son agencement dépend du support).

Warning
Un design responsive vient avec ses contraintes (duplication de code, augmentation du volume du site à télécharger par le client, complexité, plus de tests end-to-end à prévoir…).

4.2.5. Progressive Web Apps (PWA)

Tip

Spécifier si l’application est progressive. Les applications PWA sont des applications Web HTML5 possédant tous les attributs des applications natives (mode déconnecté, rapide, adaptatif, accessible depuis l’OS, …)

Exemple : L’application X sera totalement PWA. Des tests devront démonter que le site continuer à fonctionner sans réseau et que les pages se chargent en moins de 5 secs en 4G.

4.2.6. Navigateurs supportés

Tip

Préciser quels sont les navigateurs supportés si votre projet contient une IHM Web.

Lorsqu’on s’adresse à un public dont on ne gère pas le parc de navigateurs (comme un site Web sur Internet), la meilleure option pour rendre les choses intelligibles et expliciter les enjeux est de négocier avec les parties prenantes du projet un pourcentage de public supporté en se basant sur des statistiques. Par exemple : "Support de 95 % des navigateurs".

Warning
Supporter d’anciens navigateur (IE en particulier) peut engendrer des surcoûts rédhibitoires et des risques sur la sécurité. Dans tous les cas, il convient d’évaluer les surcoûts de tester sur plusieurs plate-formes. Il existe de bons outils (payants) comme Litmus ou EmailOnAcid permettant de générer un rendu des sites Web et des courriels HTML sur une combinatoire d’OS / type de lecteur (PC/tablette/mobile) /navigateur très vaste (de l’ordre de 50). Ce type de site est incontournable pour une application grand public.

Exemple 1 : L’application intranet X devra fonctionner sur les navigateurs qualifiés en interne (cf norme xyz)

Exemple 2 : L’application Y étant une application internet visant le public le plus large possible, y compris des terminaux de pays en voie de développement. Il devra supporter Firefox 3+, IE 8+, Opera 6+.

Exemple 3 : L’application Z vise le public le plus large et doté de systèmes raisonnablement anciens et devra donc supporter : Firefox 6+, Chrome 8+, Opera 8+, IE 10, Edge.

4.2.7. Internationalisation (i18n)

Tip

Préciser les contraintes de l’ application en terme d’i18n : localisation des libellés, direction du texte, mise en page adaptable, code couleur spécifique, format de dates, devises, affichage des séparateurs décimaux, etc.

Exemple 1 : L’IHM X sera traduite en 25 langues dont certaines langues asiatiques et l’arabe.

Exemple 2 : les formats de dates et autres champs de saisie devront être parfaitement localisés pour un confort maximal de l’utilisateur.

4.2.8. Mode déconnecté

Tip

Préciser si l’application doit pouvoir continuer à fonctionner sans accès à Internet ou au LAN (très courant pour les applications utilisées par les professionnels en déplacement par exemple).

Il peut s’agir de clients lourds classiques (Java, C, …) possédant leur base locale pouvant être synchronisée de retour au bureau. Il peut également s’agir d’applications PWA (voir plus haut) utilisant un service worker pour les resources statiques et du stockage navigateur (local storage, base de données IndexedDB).

Exemple 1 : L’application sera développée en Java Swing avec stockage local basé sur une base H2 synchronisées avec la base commune par appels REST.

Exemple 2 : L’application mobile sera en mode PWA, entièrement écrite en HTML5 avec local storage pour stocker les données de la journée dans le navigateur.

4.3. Exigences de SEO

Tip

Le SEO (Search engine optimization) concerne la visibilité d’un site Web au travers des moteurs de recherches (comme Google ou Quant).

Exemple 1 : Aucune indexation nécessaire ni désirée (site interne)

Exemple 2 : Les pages statiques du site devront suivre les bonnes pratiques SEO pour optimiser sa visibilité.

4.4. Exigences d’écoconception

Tip

L’écoconception consiste à limiter l’impact environnemental des logiciels et matériels utilisés par l’application. Les exigences dans ce domaine s’expriment généralement en WH ou équivalent CO2.

A noter que la loi française (voir loi du n°2020-105 du 10 février 2020, ou loi AGEC) exige de réduire le gaspillage lié au numérique, notamment concernant l’obsolescence logicielle (art. 27).

Lister ici les exigences d’écoconception portant sur les logiciels.

Exemple : Les émissions cumulées du service A ne devrait pas dépasser 100KgCO2/an.

5. Architecture cible

5.1. Pile logicielle

5.1.1. Filière technique retenue

Tip

Donner les technologies choisies parmi les technologies au catalogue de l’organisation. S’il existe des écarts avec le catalogue, le préciser et le justifier.

Exemple : cette application est de profil P3 : "Application Web Spring" avec utilisation exceptionnelle de la librairie JasperReport.

Exemple : Utilisation de Reacts.js à titre expérimental au sein de l’organisation. Validé en commité architecture le …

5.1.2. Composants logiciels

Tip

Lister ici pour chaque composant les principales librairies et frameworks utilisés ainsi que leur version. Ne pas lister les librairies fournies au runtime par les serveurs d’application ou les frameworks. Inutile de trop détailler, donner uniquement les composants structurants.

Exemple :

Table 4. Exemple de pile logicielle
Librairie Rôle Version

Framework Angular2

Framework JS de présentation

2.1.1

JasperReport

Editique transactionnelle, composition des factures au format PDF

6.3.0

5.2. Performances

Important
Les exigences sont dans la vue dimensionnement.
Tip

Même si des campagnes de performance sont prévues, l’expérience montre que la plupart des problèmes de performance auraient pu être détectés dès le développement. Il est donc important que les développeurs profilent leur code, dès leur poste de travail (à prévoir dans le Definition Of Done du projet). Il ne sera pas possible de détecter tous les problèmes (scalabilité, concurrence, robustesse, tuning des caches, …) mais la plupart des problèmes de temps de réponse. Il est également souvent possible de simuler de la concurrence et de la charge. Nous présentons ici quelques pistes très basiques et à la portée de tout développeur.

Coté Frontend :

  • Limiter la complexité des CSS (sélecteurs ou fonctions en particulier)

  • Utiliser un profiler (comme celui de Chrome)

  • Privilégier les appels asynchrones

Coté Backend :

  • S’assurer que la pagination serveur va bien jusqu’à la base de donnée (utiliser FETCH FIRST x ROWS ONLY mais pas LIMIT and OFFSET).

  • Ne pas mettre en place de contraintes inutiles en base de données.

  • Limiter le nombre de jointures et les relations many-to-many.

  • Dans des cas de grosses volumétries, étudier les solutions de partitionnement de tables.

  • Ne pas oublier d’ajouter tous les index nécessaires, utiliser l’analyse du plan d’exécution pour vérifier qu’il n’y a pas de full scans.

  • Attention aux fonctions SQL qui 'cassent' les index (comme UPPER()). Privilégier les traitements coté code backend si possible.

  • Activer les logs de requêtes (exemple Hibernate : org.hibernate.SQL=DEBUG,-Dhibernate.generate_statistics=true) et vérifier les requêtes SQL et leur nombre (pour détecter en particulier le problème du SELECT N+1, très courant).

  • Disposer même sur poste de travail d’un jeu de donnée minimal (une centaine d’enregistrement).

  • Vérifier avec un profiler (comme JVisualVM en Java) la consommation mémoire pour détecter les fuites ou les surconsommations.

  • Vérifier qu’il n’y a pas de fuite de threads ou de deadlocks en comptant le nombre de threads actifs sur une période suffisamment longue (une nuit complète par exemple).

  • Stresser les API a minima (avec des injecteurs comme JMeter ou K6) et via une rampe progressive.

  • Traquer les IO (des millions de fois plus lents que des accès mémoire).

Frontend et backend :

  • Toute ressource (taille de chaîne, nombre d’appel sur une durée, …) doit systématiquement être bornée par une limite (pas d’open bar).

  • Vérifier que la taille des requêtes HTTP reste en dessous de quelques dizaines de Kio (hors GET sur fichiers). Utiliser la pagination cliente et serveur.

  • Traquer le bavardage réseau : grouper les requêtes quand possible (il faut trouver un compromis avec la règle précédente). S’aider de la règle ‘I’ de SOLID (Interface Segregation).

  • Prévoir des endpoints multivalués (exemple: GET /personnes?list=id1,id2…) pour récupérer plusieurs éléments à la fois (doit se concrétiser par un seul SELECT WHERE .. IN dans la requête finale, pas une boucle dans le code !)

Warning
Ne pas tomber à l’inverse dans l’optimisation prématurée "source de tous les problèmes" selon Donald Knuth. Écrire le code le plus simple possible et suivre un bon design, ne l’optimiser qu’ensuite. N’optimiser que si cela vaut le coût (loi de Pareto). Commencer par les optimisations les plus significatives et ne pas perdre son temps à grappiller des microsecondes voire nanosecondes.

5.3. Spécificités d’usine logicielle

Tip

Sans reprendre le fonctionnement de la PIC (Plate-forme d’Intégration Continue) de l’organisation, préciser si ce projet nécessite une configuration particulière.

Exemple : Les jobs Jenkins produiront le logiciel sous forme de containers Docker si tous les TU sont passants. Les tests d’intégration seront ensuite exécutés sur ce container. Si tous les tests d’intégration et BDD sont passants, l’image Docker est releasée dans Nexus.

5.4. Bonnes pratiques

Tip

Lister les bonnes pratiques (blueprints) applicables. Éviter les bonnes pratiques 'maison' mais privilégier celles qui viennent de la communauté et sont donc éprouvées et déjà connus des développeuses et développeurs. Idéalement, il ne devrait y avoir ici que les liens vers des ressources externes.

Exemple : Suivre les recommendations de ce tutoriel pour la conception d’API Restful.

5.5. Normes de développement et qualimétrie

Tip

Rendre explicite les règles et le niveau de qualité requis pour le code

Exemple 1 : Les règles de qualité à utiliser pour le code seront (les règles standards SonarQube pour Java).

Exemple 2 : Le niveau de qualité exigé correspond au Quality Gate SonarQube recommandé :

  • 80% de couverture de code minimum

  • 3 % max de lignes dupliquées

  • Niveau A en Maintenabily, Relability et Security

Exemple 3 : Quelle langue utilisée pour le code ? français pour les termes fonctionnels (il est impératif d’utiliser les termes métiers comme préconisé par le DDD) et l’anglais pour les termes techniques génériques.

5.6. Patterns notables

Tip

Préciser si ce projet a mis en œuvre des patterns (GoF, JEE ou autre) structurants. Inutile de reprendre les patterns déjà supportés par les langages ou les serveurs d’application (par exemple, l’IoC avec CDI dans un serveur JEE 6).

Exemple 1 : pour traiter l’explosion combinatoire des contrats possibles et éviter de multiplier les niveaux d’héritage, nous utiliserons massivement la pattern décorateur [GoF] dont voici un exemple d’utilisation : <schéma>.

5.7. Spécificités des tests

Tip

Une méthodologie ou une technologie particulière est-elle en jeu dans ce projet ? Quelle est la stratégie de tests ?

Exemple 1 : ce projet sera couvert en plus des TU et tests d’intégration car des tests d’acceptance BDD (Behavioral Driven Development) en technologie JBehave + Serenity.

Exemple 2 : ce projet sera développé en TDD (test first)

Exemple 3 : Types de tests

Table 5. Types de tests
Type de test Temps à investir Manuel ou automatisé ? Type de module ciblé Taux de Couverture visée Détail

TU

Très élevé

Automatisé

Backend et Frontend

env. 80%

Format BDD : spécifications de comportements des classes et méthodes

Spécifications exécutables

Très élevé

Automatisé

Api

env. 100% pour les classes du domaine

Mode bouchonné.

Tests de contrats

Faible

Automatisé

Liens UI/API

env. 100% du code appelant coté UI et des contrôleurs Spring coté API

Teste la non régression des échanges lors de l’appel des opérations des API REST (principe CDC=Consumer-Driven Contract) via les outils Pact et pact-react-consumer.

Tests d’architecture

Très faible

Automatisé

API et batchs

N/A, 100% du code est validé par l’outil

En particulier, ces tests simples à écrire vérifieront le respect des règles de l’architecture hexagonale. Utilisation du framework de test ArchUnit.

TI (tests d’intégration)

Faible

Automatisé

Composants appelant des systèmes externes (bases de données, API…)

50 à 60%

Chaque TI ne doit tester qu’un seul système externe à la fois

E2E (tests bout en bout)

Faible

Automatisé

UI

30%, cas nominaux (happy path)

Ecrits en CodeceptJS, Selenium ou technologie similaire. Ils seront limités à un rôle de smoke tests (détection de problèmes grossiers). Ces tests ne seront pas bouchonnés mais seront effectués sur chaîne de liaison instanciée de bout en bout. Pour éviter le travail inutile, ces tests seront faits au niveau de features entières, pas forcément à chaque sprint. Ces tests feront office également de tests système puisqu’ils solliciteront un maximum de modules débouchonnés.

Tests de performance

Faible (hors campagnes de performance dédiées)

Automatisé

API critiques

20%

Possiblement automatisés en CI en DEV mais également lancé manuellement par les développeurs

Tests d’accessibilité

Moyenne

Automatisé + manuel

UI

50%

Tests Axe-Core lancés en CI à compléter d’un audit manuel

Tests de sécurité

Moyenne

Manuel

Tous

Faible, uniquement sur les fonctions sensibles

Audit à prévoir

Tests système

Faible

Manuels

UI et batchs

10%

Tests menés par l’équipe de développement couvrant des scénarios fonctionnels complets. Le but est ici de tester le fonctionnement de l’ensemble des modules (ce qui n’est pas automatisable) et de détecter un maximum de bugs avant les tests d’UAT.

Tests UAT (acceptance)

Moyenne

Manuels

UI, batchs lancé à la main

de 30% à 80% selon le nombre de scénarios prévus

Tests menés en recette par des utilisateurs finaux sur environnement non bouchonné avec des cahiers de tests. Tests d’acceptance de bout n bout (on suit un cahier de tests avec les cas nominaux), Tests exploratoires (on tente toutes les combinatoires possibles avec un guidage minimal dans le cahier de test)

Note
Pour un projet d’envergure, la stratégie de test fait en général l’objet d’un document propre. Une stratégie standard peut également être définie au niveau du SI.

5.8. Éco-conception

Tip

Lister ici les mesures logicielles permettant de répondre aux exigences d’écoconception listées plus haut. Les réponses à ces problématiques sont souvent les mêmes que celles aux exigences de performance (temps de réponse en particulier). Dans ce cas, y faire simplement référence. Néanmoins, les analyses et solutions d’écoconception peuvent être spécifiques à ce thème.

Un point de départ intéressant pour manipuler l’impact carbone peut être la formule SCI (Software Carbone Intensity):

SCI = ((E * I)) + M) par R

Avec:

  • E (kWh) : L’énergie totale consommé par le logiciel ;

  • I (gCO2/kWh), la quantité de carbone émis par kwH ;

  • M (gCO2) : l’empreinte carbone du hardware ;

  • R: la quantité de référence (ex: par utilisateur, par appareil, …​)

Quelques pistes d’amélioration énergétique du projet :

  • Utiliser des profilers ou des outils de développement intégrés dans les navigateurs (comme Google Dev Tools) pour analyser la consommation de ressources (nombre, durée et taille des requêtes).

  • Pour les apps, utiliser des outils de supervision de la consommation de batterie comme Battery Historian.

  • Utiliser la suite d’analyse spécialisée Greenspector.

  • Mesurer la consommation électrique des systèmes avec les sondes PowerAPI2 (développé par l’INRIA et l’université Lille 1).

  • Mesurer la taille des images et les réduire (sans perte) avec des outils comme pngcrush, OptiPNG, pngrewrite ou ImageMagick.

  • Optimiser la consommation mémoire et CPU des applications, tuner le GC pour une application Java.

  • Faire du lazy loading pour le chargement des ressources occasionnelles.

  • Limiter les résultats retournés de la base de donnée (pagination).

  • Grouper les traitements de masse dans des batchs qui seront plus efficaces (lots).

Exemple 1 : le processus gulp de construction de l’application appliquera une réduction de taille des images via le plugin imagemin-pngcrush.

Exemple 2 : des tests de robustesse courant sur plusieurs jours seront effectués sur l’application mobile après chaque optimisation pour évaluer la consommation énergétique de l’application.

Exemple 3 : Les campagnes de performance intégreront une analyse fine de la consommation de bande passante et en cycles CPU même si les exigences en temps de réponses sont couvertes, ceci pour identifier des optimisations permettant de répondre aux exigences d’éco-conception si elles ne sont pas atteintes.

Exemple 4 : Pour une exigence de 100KgCO2/an maximum emit par le service en ligne A : on utilise 20% d’un serveur physique. On estime l’intensité carbone du serveur hors fonctionnement à 1.5TCO2 sur tout son cycle de vie de 10 ans (donc 30 kgCO2/an au prorata du service A).

En utilisant la formule SCI (voir plus haut), et pour une consommation totale du serveur de 800W et 20K appels par heure en moyenne, et une électricité française d’intensité carbone de 63g/KWH, on ne doit pas dépasser E=1111 KWH/an, soit 6.34 mWH/appel.

5.9. Gestion de la robustesse

5.9.1. Gestion des transactions

Tip

Lister ici les décisions prises concernant la gestion des transactions. Ceci est surtout utile pour un système distribué. Quelques exemples de problématiques :

  • Autorise-t-on les mises jours sur de multiples composants lors d’une même requête ?

  • Si oui, assurons nous le caractère ACID du tout (via le mode XA par exemple) ?

  • Quel moteur transactionnel utilisons nous ?

  • Quel niveau d’isolation transactionnelle (read commited, uncommited, repeatable read, serializable) ?

  • Si aucun moniteur transactionnel n’est utilisé (appel de plusieurs services REST en mise à jour par exemple), prévoit-t-on des transactions compensatoires en cas d’échec de l’une des mises à jours ?

Exemple : nos ressources n’étant pas transactionnelles (services REST), et voulant éviter de faire des transactions compensatoires, il est interdit d’appeler deux services en mise à jour de façon synchrone. Au besoin, nous utiliserons une file pour effectuer des mises à jour au fil de l’eau.

5.9.2. Gestion des sessions

Tip

Comment gère-t-on les sessions HTTP permettant de fournir un contexte d’exécution à un utilisateur (exemple: son panier d’achat) ?

Notez que ceci est une surtout un problème pour les applications Web classiques dont la présentation est générée sur le serveur, pas pour les applications SPA (Single Page Application) qui gèrent toute la présentation et leur état en local dans le navigateur.

Les choix faits ici affecteront les choix d’infrastructure. Par exemple, si une session est requise et que l’infrastructure est en cluster, il faudra soit mettre en place de l’affinité de session sur les serveurs pour forcer chaque utilisateur à toujours arriver sur le même serveur disposant de ses données, soit de mettre en place un cache distribué permettant aux serveurs de partager les sessions de tous les utilisateurs (plus complexe).

Exemples de points à traiter :

  • Quelles données doivent être conservées en session ? (attention à la volumétrie, surtout si cache distribué)

  • Le code doit-il être thread-safe (si le même utilisateur ouvre un autre onglet dans son navigateur par exemple) ?

Exemple : notre application JSF stockera en session HTTP uniquement son panier d’achat, pas les références produits

5.9.3. Gestion des erreurs

Tip

Comment gère-t-on erreurs ? Exemples de points à traiter :

  • Différencions-nous erreurs fonctionnelles (erreurs fonctionnelles prévues) et techniques ? Prévoir un diagramme de classe.

  • Comment logue t-on les erreurs ? quel niveau de log ?

  • Où sont attrapées les exceptions ? au plus tôt ou en début d’appel de façon centralisée ?

  • Utilise-t-on les exceptions standards du langage (IOException…) ou notre propre jeu d’exceptions ?

  • La liste des erreurs est-elle consolidée ? documentée ?

  • Affecte-t-on des codes erreur ?

  • Affiche-on les stack-traces complètes ? si oui, coté serveur et coté client ?

  • Gère-t-on les rejeux ? si oui, espace-t-on les rejeux ? de façon aléatoire (jitter) ? exponentielle (exponential backoff) ?

  • Comment gère-t-on les timeouts ?

  • Comment gérons-nous les rejets fonctionnels? (c.-à-d. que faire des demandes partielles ou erronées?)

Exemple : les erreurs techniques (imprévues) comme le timeout à un appel de service REST sont catchées au plus haut niveau de l’application (via un ErrorHandler). Toutes ses informations sont loguées avec la stack-trace complète mais l’appelant ne doit recupérer que le code erreur générique XYZ sans la stack-trace (pour raison de sécurité).

5.9.4. Gestion de la robustesse coté frontend

Tip

Tout comme le backend, le frontend requiert une robustesse importante, d’autant plus qu’il est en prise directe avec l’interface chaise-clavier.

Entre autres :

  • Penser à interdire les doubles soumissions (double appel au backend si on double-clic sur un bouton). Ceci n’exclut pas de procéder à des contrôles de durcissement coté backend.

  • Afin d’éviter des problèmes subtils (surtout en cas d’utilisation de stockage navigateur comme les local/session storage), penser à empêcher l’ouverture d’une même application Web dans plusieurs fenêtres ou onglets du navigateur. En cas de tentative, afficher un message d’erreur dans les fenêtres surnuméraires.

  • Toujours vérifier la comptabilité du navigateur, même en environnement contrôlé. En cas de tentative d’ouverture d’une page par un navigateur non supporté, afficher un message d’erreur explicite à l’écran.

Exemple 1 : Si l’application est ouverte avec IE, un message d’erreur doit inviter l’utilisateur à utiliser un navigateur supporté.

Exemple 2 : Tous les boutons de l’application devront interdire la double soumission en désactivant temporairement les bouton sur événement.

5.10. Gestion de la configuration

Tip

Comment configure-t-on l’application ? Exemples de points à traiter :

  • Quelles sont les variables incluses dans le package final de façon statique ?

  • Quels sont les paramètres modifiables au runtime ?

  • Mon application est-elle paramétrable via feature flags pour des raisons de canary testing par exemple ? si oui, comment je le gère dans le code ?

  • Sous quelle forme les paramètres sont-ils injectés dans l’application (variable d’environnement ? fichier .properties, base de donnée, …) ?

  • L’application accepte-elle une modification du paramétrage à chaud ?

  • Décrire le système de configuration

Exemple (application déployées dans Kubernetes) :

La configuration sera injectée au lancement (non modifiable à chaud) via des variables d’environnements fournies dans le descripteur de déploiement Kubernetes.

5.11. Politique de gestion des branches

Tip

Quels sont des workflows de branche à prévoir ? git-flow ? TBD (Trunked-based Development) ? autre ?

Exemple :

  • La politique générale adoptée est la TBD (Trunk-Based Development)

  • La branche principale est develop. Il s’agit d’une branche protégée vers laquelle il n’est pas possible pousser de commits.

  • Tout commit devra faire l’objet d’une Merge Request avant intégration dans develop. Les critères de qualité (évalués de façon automatique lors de l’intégration continue) devront être atteints pour que le commit soit intégré.

  • Chaque fonctionnalité, refactoring significatif ou bugfix sera donc réalisé sur une branche topic dédiée.

  • Une branche de maintenance sera tirée sur chaque tag de version x.y. Seuls les bugfixs seront mergés dans les branches de maintenance depuis develop via des cherry-pick.

5.12. Versioning

Tip

Que versionne-t-on et quel système de version utilise-t-on ?

Exemple:

  • D’une façon générale, toute ressource non dérivée (source, outil, script de ci-cd, template, DDL de base de données, …) doit être versionnée.

  • Les modules seront versionnés suivant la numérotation x.y.z (<majeur).<évolution>.<fix>)

  • Les librairies seront versionnées suivant la même numérotation que les modules mais la valeur x sera incrémentée lors de toute montée de version cassant la compatibilité ascendante (principe du Semantic Versioning).

  • La version logique globale du projet sera : <lot>.<no sprint>.<déploiement>

5.13. Gestion de la concurrence

Tip

Comment gère-t-on les accès concurrents ? Exemples de points à traiter :

  • Quel scope pour les objets (si utilisation d’un moteur IoC) ?

  • Les objets doivent-il être thread-safe ?

  • Quelles méthodes doivent être synchronisées ?

  • Risques de race condition ? de starvation ? de dead locks ?

Exemple (Spring MVC) : Tous les controllers seront en scope singleton et ne doivent donc en aucun cas stocker d’état dans leurs attributs pour éviter des race conditions.

5.14. Encodage

Tip

Quelles sont les règles concernant l’encodage des chaînes de caractère ? Ceci est un problème récurrent dans les SI (qui n’a jamais observé d’accents corrompus sous forme de carrés ?). Ce problème est pourtant relativement simple à résoudre et n’exige que de la rigueur. Voir les exemples ci-dessous pour des exemples de dispositifs effectifs.

Exemple 1 : Le seul encodage autorisé dans tous les modules et composants techniques est l’UTF-8. L’utilisation de l’ISO-8859-1, CP-1252 ou de tout autre encodage est formellement proscrit. Ceci comprend le paramétrage des serveurs d’application (Node, Tomcat…), des sources, des fichiers de configuration, des bases de données et des fichiers.

Note
Dans certains cas, nous n’avons pas la main sur la lecture des .properties (depuis un framework par exemple), il n’est alors pas possible de forcer un encodage en UTF-8.

Exemple 2 : Si un système externe impose d’envoyer ou de recevoir des chaînes de caractères dans un encodage autre que le UTF-8 (exemple : un service REST qui renvoi des données en ISO-8859-1) et qu’il n’est pas possible de modifier le contrat, il est impératif de traduire au sein d’une couche anti-corruption les chaînes de caractères et ceci au plus tôt, dès l’appel. De plus, il ne faut jamais persister dans nos systèmes une donnée dans un encodage non UTF-8.

5.15. Fuseaux horaires

Tip

Comment gère-t-on le stockage des dates ? Ceci, comme la gestion de l’encodage est un problème récurrent (décalage d’un jour, bugs lors des changements d’heure d’été/hiver, etc.) et pourtant simple à résoudre : suivre la norme ISO 8601 ("Time zones in ISO 8601 are represented as local time (with the location unspecified), as UTC, or as an offset from UTC." [Wikipedia]).

Exemple 1 : Les heures ne seront jamais stockées sans fuseau horaire. En base, on utilisera des timestamps avec timezone (timestamptz) et en Java ou JS, des objets intégrant le fuseau horaire de façon explicite (ex: Instant et pas LocalDateTime en java) ou des epochs. La précision sera au moins de la milliseconde.

Exemple 2 : Les dates et date-heures seront stockées en base de données comme epoch millis au format entier long. Dans le cas des dates, on stockera l’epoch millis à 12:00 UTC (et pas 00:00, trop proche du jour précédent, risque de bug).

5.16. Gestion des logs

Note
Les aspects d’infrastructure de logs sont détaillés dans la vue infrastructure.
Tip

Donner ici les règles générales concernant les traces applicatives (logs), les niveaux et quantité de logs. Penser à l’exploitation des logs, surtout coté serveur. Se demander s’il sera possible d’en tirer profit en cas d’erreur en production au milieu de Mio voire Gio d’autres logs et de n threads loguant en parallèle.

5.16.1. Règles générales

Exemple 1 :

  • Ne pas laisser de logs de développement dans le code (exemple : console.out("entrée dans méthode x") ou e.printStackTrace())

  • Penser à utiliser des chaînes de caractère discriminantes (exemple : code erreur) pour faciliter le filtrage dans l’outil de recherche de logs.

  • Toujours fournir des identifiants d’entités permettant de retrouver l’objet concerné

  • Utiliser des identifiant de corrélation entre tiers (exemple : id de traitement générée coté client en JS, passée au serveur)

  • Eviter les calculs coûteux (exemple: beaucoup de concaténations) et utiliser des blocs conditionnels (exemple en Java :

if (isDebugEnabled()){
   logger.debug(a+b+c)
}

5.16.2. Niveaux et quantité de logs

Tip

Expliquer quand et quoi loguer de sorte à produire des logs exploitables en production.

Exemple :

Table 6. Niveaux logs
Niveau de gravité Contexte d’utilisation Volume indicatif Environnement

DEBUG

En environnement de développement, il permet d’afficher les valeurs de variables, E/S de méthodes etc..

Max quelques Mio / minute

DEV, Recette. Interdit en PROD sauf demande expresse du projet

INFO

Début/fin d’un batch ou d’un appel, chargement d’une nouvelle propriété. Peut être utilisé sous forme condensée pour les appels de service (logging d’un appel et de son contexte). C’est le niveau de prolixité utilisé pour la métrologie.

Max 10 logs / sec, quelques Kio / minute

Tous

WARN

Tous les messages d’avertissement sur les informations fonctionnelles inattendues

Pas de limites mais ne pas en abuser et y positionner un maximum de détail de contexte

Tous

ERROR

Toutes les erreurs qui n’empêchent pas à l’application de fonctionner.

Pas de limites. Positionner un maximum de détail de contexte

Tous

FATAL

Toutes les erreurs bloquantes pour l’application (problème d’accès BDD, HTTP 404 ou 500). Positionner un maximum de détail de contexte. Penser à bien logger ces erreurs sur un appender console au cas où l’écriture sur FS serait impossible (disque plein). Penser que lors d’une erreur fatale, l’écriture même du log est sujette à caution (par exemple en cas de dépassement mémoire).

Pas de limites.

Tous

5.17. Outils d’administration

Tip

L’application doit-elle fournir des services d’administration ? Il est fortement conseillé (c’est le facteur 12 des Twelve factors d’Heroku) d’intégrer le code d’administration directement avec le code métier.

Exemples de points à traiter :

  • Dois-je fournir un moyen de purger des données, logs, caches, … ? (on appelle quelque fois ce type de service un 'traitement interne')

  • Dois-je fournir des indicateurs applicatifs de supervision ? (nombre de dossiers consultés, …) ?

  • Dois-je fournir des outils de migration ?

Exemple : Le service /interne/maj_2 effectuera une montée de version du modèle de donnée vers la V2

5.18. Tri et Pagination

Tip

Il est nécessaire de conserver une bonne fluidité de récupération des données en lot. La pagination permet de limiter le bavardage entre les clients (IHM et batchs) et les API. Décrire ici les dispositifs de pagination mis en ouvre coté client et coté serveur.

Exemple 1 (Coté serveur)

  • Les requêtes en sortie de l’api sont systématiquement triées selon un ordre ascendant (le défaut) ou descendant. De plus, il sera possible de choisir le champ sur lequel se fait le tri via un autre query param.

  • Afin de limiter le nombre de requêtes à destination de l’api, celle-ci retourne un nombre limité d’éléments (ce nombre sera paramétrable suivant la taille des éléments individuels). Il s’agit du query param range contenant le numéro de la page à récupérer + le nombre d’éléments de la page. Chaque API proposera une valeur par défaut (de l’ordre d’une centaine).

Exemple 2 (Coté client)

  • Le tri doit s’appliquer sur l’ensemble des éléments en base, pas seulement sur les éléments de la dernière requête retournée par le serveur.

  • Les éléments retournés seront affichés dans les tableaux par blocs (taille paramétrable d’une taille indicative de l’ordre de 20 éléments).

5.19. Provisioning et mises à jour des DDL

Tip

Décrire comment les DDL (structures de tables en base de données) et les données initiales (comme des nomenclatures) seront gérées puis mis à jour.

Exemple : Nous utiliserons Liquibase embarqué dans les war pour créer et mettre à jour les DDL de la base. Il n’y aura donc pas de scripts SQL à lancer, les requêtes nécessaires seront effectuées directement par l’application lors de son démarrage.

5.20. Gestion de l’i18N

Tip

Décrire comment vous répondez aux exigences d’internationalisation exprimées plus haut.

Exemple : La gestion des dates, pluriels et nombres se fera via le standard ICU et la librairie JS messageformat.