Accueil > 12 Factor-App : les patterns à adopter dans le développement d’applications modernes
Mohamed Ben Slimen
1 mars 2022
Read this post in English

12 Factor-App : les patterns à adopter dans le développement d’applications modernes

12 Factor-App : les patterns à adopter dans le développement d’applications modernes

Article corédigé par Mohamed Ben Slimen (Cellenza) et Mahdi Ghandri (Squadra)

 

La relation ou la dépendance entre l’univers du Build et du Run n’est plus à démontrer de nos jours. En effet, avec les changements qu’ont subis nos habitudes de développement d’applications web, ou les applications dites Cloud natives avec la démocratisation du « You build it, you run it », ou par l’adoption des méthodes dites « DevOps », nous avons de plus en plus besoin d’une méthodologie mettant le Build au service du Run.

En 2012, les équipes IT de la société américaine Heroku se sont basées sur des centaines de retours d’expériences de leurs équipes de développement et d’exploitations, et ont publié un manifeste dans lequel elles définissent les 12 règles à suivre dans la conception, le développement d’applications modernes. On les appelle les « Twelve Factor-App ».

Ces principes sont universels, indépendants du langage et du framework utilisés et peuvent être appliqués quels que soient vos outils ou frameworks.

Nous vous proposons de découvrir ces 12 facteurs.

 

Livre blanc Run Cellenza

 

I. Codebase

 

“One codebase tracked in revision control, many deploys”

 

Le principe d’une base de code définit qu’une application ne peut être archivée et versionnée dans plusieurs dépôts de code source et inversement.

Ainsi, un dépôt de code source ne peut contenir qu’une seule application à la fois. Chaque commit vers ce dépôt unique pourra faire l’objet d’une génération d’artefacts qui seront déployés vers un ou plusieurs environnements d’exécution de l’application (test, recette ou production). En revanche, les ressources comme les scripts de « build » ou de « release » (tels que les fichiers YAML), les scripts de provisionning des ressources (comme les fichiers Terraform) peuvent être intégrés dans cet unique dépôt.

En cas d’anomalie ou de bug, un simple « rollback » du commit en question suffira pour revenir à un état stable de l’application.

Si plusieurs applications partagent la même base de code, il sera préférable de factoriser la partie de code en question qui sera publiée depuis un autre dépôt comme une dépendance externe.

 

II. Dependencies

 

“Explicitly declare and isolate dependencies”

 

Une dépendance est un élément externe mais essentiel pour l’application. Les dépendances représentent l’unique élément sur lequel nous n’avons aucune maîtrise. C’est pour cette raison qu’il faut leur attribuer un niveau de vigilance accrue!

Une application 12 facteurs doit :

  1. Identifier de manière explicite ces dépendances (nom du package + version) ;
  2. Isoler les dépendances du reste du code, le code est l’unique pièce pertinente ;
  3. Les dépendances doivent être immuables : il ne faut pas faire de supposition sur le fait qu’une dépendance existe dans les environnements d’exécution ;
  4. Lister les dépendances. Cette liste sera utilisée lors de la phase de Build et du déploiement ;
  5. Vérifier que l’intégrité des dépendances est satisfaite.

 

Voici quelques outils qui, selon la technologie utilisée, vous aideront à suivre les dépendances de votre application :

  • NUGET => .Net
  • Maven => JAVA
  • NPM => NodeJs
  • Bundler => RUBY

 

III. Config

 

“Store config in the environment”

 

Par définition, la configuration d’une application renvoie à l’ensemble des variables qui dépendent de l’environnement : chaînes de connexion aux espaces de stockage, URLs vers des APIs externes ou vers des services internes tels que les namespaces des services Bus, ou même un simple serveur SMTP pour l’envoi des emails.

Les données de configuration vont plus porter sur des données sensibles telles que les mots de passe de la base de données ou les identifiants d’authentifications. Il est donc nécessaire de les protéger en les séparant du reste du code de l’application

Par exemple, un coffre-fort comme Azure Key Vault permet de garder secrètes des valeurs de configurations sensibles et de les servir via des URLs pour les applications clientes.

Un autre avantage de cette méthode est de pouvoir attribuer des valeurs différentes aux variables selon l’environnement cible : test ou production.

⚠️Attention à ne pas confondre avec les paramètres de l’application qui ne sont pas changés avec l’environnement mais plutôt avec les scénarios d’utilisation, comme par exemple : le thème à appliquer à l’interface, la durée des sessions utilisateurs, etc.

Pour toutes ces raisons, dans les applications 12 facteurs, les informations de configuration doivent être injectées par l’environnement d’exécution sous forme de variables d’environnement et sont ainsi strictement séparées du code.

 

IV. Backing services

 

“Treat backing services as attached resources”

 

Le quatrième principe stipule que les services tels que les services bus, les base de données, les services de mailing, les espace de stockage, etc. doivent être considérés comme des ressources externes et découplés de l’application.

La consommation et l’utilisation de ces ressources se fera via des urls ou des points d’accès similaires qui seront spécifiés dans des variables d’environnement (voir principe n°3 : Config).

L’objectif est, en cas de défaillance, de pouvoir interchanger (détacher / attacher) ces ressources sans impacter le fonctionnement ni avoir besoin de changer le code de l’application.

 

V. Build, release, run

 

“Strictly separate build and run stages”

 

Les applications 12 facteurs séparent le processus de déploiement en 3 étapes :

  • Assemblage : il s’agit de la génération des artefacts depuis le code source. Durant cette étape, le code est d’abord extrait depuis la source et est contrôlé avec le compilateur (vérification syntaxique). Les binaires (.exe , dll , jar, etc.) sont ensuite générées et le code est testé à l’aide de tests unitaires et analysé afin de contrôler sa qualité. Les artefacts de sortie sont stockés dans des zones de stockage, accessibles par le service de « publication ».
  • Publication : une fois la génération des artefacts terminée, c’est à l’étape de publication que ces artefacts sont déployés vers les environnements cibles en appliquant les configurations requises. La publication doit être immuable, versionnée et ne doit pas subir d’autres changements.
  • Exécution : cette étape regroupe l’ensemble des tâches suivantes :
    • le provisionnement des environnements tels que l’exécution des scripts Terraform ou les scripts de migration de base de données ;
    • le déploiement de la publication des fichiers binaires, dépendances, etc.
    • l’exécution de l’application avec le lancement d’un ou de plusieurs processus.

Ainsi, le processus de déploiement est complètement éphémère. Tous les artefacts et environnements peuvent être reconstitués à partir de zéro en utilisant les actifs stockés dans le référentiel de code source.

Une approche CI/CD (Continuous Integration / Continuous Delivery) est fortement recommandée pour appliquer ce principe.

 

VI. Processes

 

“Execute the app as one or more stateless processes”

 

Dans une application 12 facteurs, les processus doivent être indépendants. Ils ne gardent aucune trace et ne font aucune supposition sur l’existence d’informations produites par d’autres processus tels que les variables de sessions, par exemple.

Une architecture sans état offre la possibilité d’une mise à l’échelle horizontale plus facile et efficace en rajoutant plusieurs processus d’exécution pour faire face à une charge de travail importante.

Dans le cas des scenarii où il est nécessaire de sauvegarder l’état ou le résultat de l’exécution d’un processus, il est préférable d’utiliser des ressources telles qu’un espace de stockage ou un serveur de cache qui peuvent être considérées et traitées comme des ressources externes.

 

VII. Port binding

 

“Export services via port binding”

 

Le principe de Port Binding permet à une application d’être auto-suffisante et identifiable sur le réseau par un numéro de port (ex : 80 pour les services http ou 443 pour du https).

Par exemple, une application de type web qui expose des services via le protocole http doit porter son propre serveur web. Ce dernier est considéré comme une dépendance externe et peut être injecté au moment de l’exécution.

Ce port interne sera associé à un port externe attribué généralement par le Cloud provider et évitera ainsi les problèmes de collision de ports avec d’autres services.

Le Scale Out (ou mise à l’échelle horizontale) est une des approches les plus modernes pour les applications 12 facteurs. Pour faire grossir votre application, la rendre scalable et élastique, vous pouvez gérer le nombre de ses instances dans le Cloud. En effet, avec le Scale Out d’une application, il est possible de transformer un unique grand processus complexe en une multitude de petit processus. Ensuite vous pouvez répartir la charge de votre application Cloud native autour de ces différents petits processus.

Le Scale Up (ou mise à l’échelle verticale) n’est pas recommandé comme un premier choix de scaling pour une application 12 facteurs. En revanche, il permet la scalabilité des machines virtuelles par exemple. Grâce au Scale Up, il est possible d’augmenter la mémoire vive, le nombre de processeurs, la capacité des disques, etc. Par ailleurs, gardez en tête que faire une mise à l’échelle verticale pour augmenter la puissance de vos machines coûte évidemment plus cher et qu’il faut bien choisir les caractéristiques de vos machines en fonction de vos besoins réels.

Pour conclure, les différents fournisseurs de Cloud ont la capacité de prendre en charge le Scale Out. Si vous concevez des applications et des processus jetables, Stateless avec une architecture Share-nothing, vous êtes bien positionné pour bénéficier des avantages du Scale Out. Vous aurez ainsi la capacité de démarrer de multiples instances concurrentes de votre application et réussir son intégration dans le Cloud en tant qu’Application 12 facteurs.

 

IX. Disposability

 

“Maximize robustness with fast startup and graceful shutdown”

 

Sur une instance Cloud, une application ainsi que son infrastructure ont un cycle de vie éphémère. Il faut savoir qu’une application 12 facteurs est disposable : cela signifie qu’elle peut démarrer ou s’arrêter très rapidement.

Par exemple, une application ne peut pas être mise à l’échelle horizontalement, déployée, mise en production ou récupérée efficacement si elle ne peut pas démarrer rapidement ou s’arrêter dans un délai court. De nombreuses applications sont écrites de telle sorte qu’elles exécutent un certain nombre de processus de longue durée au démarrage : c’est le cas par exemple de la récupération de données pour remplir un cache ou préparer d’autres dépendances d’exécution. Il faut savoir que pour adopter une architecture Cloud native, ce type d’activité doit être traité séparément.

Par exemple, vous pouvez externaliser le cache dans un service de support (backing service) afin que votre application puisse monter et descendre rapidement sans effectuer d’opérations frontales (Front-Loaded Operations).

 

X. Dev/Prod parity

 

“Keep development, staging, and production as similar as possible”

 

Le facteur « Dev and Prod parity » nous recommande de garder nos environnements les plus similaires possible.

A l’époque actuelle, de nombreuses organisations cherchent à évoluer et renforcer l’innovation dans leurs systèmes d’informations d’une manière rapide et efficace. En tant que consultants IT, nous sommes fréquemment confrontés aux situations suivantes et qui peuvent s’avérer pénibles pour certains :

  • Un environnement de développement avec une fiabilité et une mise à l’échelle différentes d’un environnent de QA « Test » ou de Recette.
  • Les pilotes de bases de données utilisés pour les environnements de développement et QA sont différents de ceux de l’environnement de Production.
  • Les règles de sécurité, pare-feu, ainsi que les paramètres de configuration des environnements sont différents.

En effet, ces exemples concrets de problèmes que nous rencontrons souvent dans le monde de l’entreprise peuvent faire peur et renforcent parfois le sentiment de manque de confiance chez les équipes de Build et de Run lors des déploiements et des mises en production.

Pour cela, l’objectif d’appliquer rigueur et discipline à la « Dev and Prod Parity » est de donner à votre équipe et à toute votre organisation la certitude que l’application fonctionnera partout. Cela signifie dans tous les environnements cibles approuvés.

En effet, alors que les possibilités de créer un décalage entre les environnements sont presque infinies, les trois facteurs les plus courants pouvant avoir un impact négatif sont généralement :

  • Le temps :

Dans de nombreuses organisations, il peut se dérouler des semaines – voire des mois – entre le moment où un développeur vérifie son code et celui où ce code passe en production. Dans ce cas-là, la plupart du temps les développeurs oublient les changements qui vont partir dans la Release, malgré l’existence des Release Notes. Plus grave encore, ils peuvent oublier ce à quoi ressemble leur code source qui avait été mis en place longtemps auparavant.

En effet , en adoptant une approche moderne, les organisations devraient s’efforcer de réduire cet intervalle de temps entre l’archivage « commit » du code et sa mise en production. Cette approche moderne nous permet de réduire le temps de déploiement du code de quelques mois/semaines à quelques heures/minutes. Par ailleurs, on peut imaginer que la dernière étape d’un véritable pipeline de déploiement continu « Continuous Deployement » devrait être seulement l’exécution de tests automatisés, pour assurer une fiabilité continue d’une application.

Pour finir, cette idée de tout automatiser, du Build jusqu’au déploiement en production, d’une manière continue, peut faire peur aux organisations. Par conséquent, une fois que les développeurs ont pris l’habitude de coder en sachant que leur code source sera mis production le même jour qu’un archivage « commit », la discipline et la qualité du code montent souvent en flèche. En effet, cela ne peut que rapporter de la valeur ajoutée pour l’entreprise en termes de qualité et de productivité.

 

  • Les personnes:

Historiquement, le type de personnes déployant les applications était directement lié à la taille de l’entreprise. En effet, dans les petites entreprises, les développeurs sont généralement impliqués dans tout, du codage au déploiement, alors que dans les grandes organisations, il y a plus de personnels, de rôles et d’équipes concernés.

En effet, le facteur Dev/Prod Parity nous indique que les développeurs et les déployeurs devraient être les mêmes personnes, ce qui a beaucoup de sens si votre cible est un Cloud public. En revanche, cette pratique n’est pas toujours vraie quand l’environnement est un Cloud privé dans une grande entreprise. De plus, certains estiment que les Devs ne devraient jamais déployer d’applications, du moins pas dans un environnement autre que celui de leur poste de travail ou de Labs.

En effet, en présence d’un pipeline de Build et de Release approprié, utilisant une stratégie « CI/CD », une application peut être déployée automatiquement dans tous les environnements applicables. Sans oublier que l’application peut toujours être déployée manuellement dans d’autres environnements basés, par exemple, sur des restrictions de sécurité au sein de l’outil de CI « Continuous Integration » et l’instance du Cloud cible.

Ainsi, si d’une simple pression de bouton, vous déployez rapidement vos applications, ou si cela se fait de manière automatique en réponse à une suite d’évènements, alors vous êtes sur la bonne voie.

 

  • Les ressources:

Lorsque nous sommes assis à nos bureaux et que nous devons mettre quelque chose en place rapidement, nous faisons tous des compromis. La nature de ces compromis peut nous laisser un peu de dette technique ou nous exposer à un échec catastrophique.

De nos jours, les développeurs disposent d’un ensemble d’outils presque infini. Il reste très peu de « bonnes excuses » pour ne pas utiliser les mêmes types de ressources dans tous les environnements. Les développeurs peuvent se voir accorder leurs propres instances de bases de données (c’est particulièrement facile si la base de données est elle-même un service sur une instance PaaS) ou, si ce n’est pas une option, des outils de conteneurs comme Docker peuvent aider à rendre les environnements « Prod like » plus accessibles aux postes de travail des développeurs.

Pour conclure, il faut savoir que lors du développement de vos applications à 12 facteurs, à chaque fois que vous validez un changement (de code source par exemple ou d’une configuration), ce dernier devrait se retrouver en Production après une courte période : il s’agit du temps nécessaire pour exécuter tous les tests (exemple : unitaires, fonctionnels, de non-régressions, etc.) et vérifier les modifications par rapport à toutes les suites d’intégration.

Si vos environnements de développement, de test et de production diffèrent (même d’une manière que vous pourriez penser sans importance), vous perdez la capacité de prédire avec précision comment votre changement de code se comportera en production.

En effet, cette confiance dans le code source allant jusqu’à la production est essentielle pour le type de livraison et de déploiement continu « CI/CD » qui permet aux applications 12 facteurs et à leurs équipes de prospérer dans le Cloud. Cela est aussi tout l’intérêt du facteur « Dev and Prod parity ».

 

XI. Logs

 

“Treat logs as event streams”

 

La journalisation applicative ou les journaux  d’évènements sont l’ensemble d’informations collectées pendants l’exécution d’une application et qui représentent l’unique source de données fiable pour le monitoring et la supervision de l’application. Ils sont aussi utilisés pour l’analyse et le dépannage en cas d’incident de production.

Traditionnellement, la responsabilité de collecter les logs, de les filtrer selon le niveau souhaité (ERROR , WARN, DEBUG, etc.), de les contextualiser et enfin de les sauvegarder dans des fichiers est souvent déléguée à l’application. Cette approcher rend l’exploitation des logs pour des fins opérationnelles ou de monitoring, compliquée et fastidieuse.

C’est pourquoi les applications 12 facteurs privilégient une vision plus dynamique où les logs seront considérés comme un flux d’évènements décrivant le comportement de l’application, sans pour autant se soucier du stockage du flux de sortie.

Cette approche permet de séparer le routage et le traitement des logs, ce qui permet d’avoir plusieurs consommateurs d’événements de journalisation mais pour des fins différentes. Par exemple, Azure Application Insight offre la possibilité d’implémenter cette approche.

 

Vue d'ensemble d’Application Insights Microsoft

Source : documentation Microsoft

XII. Admin processes

 

“Run admin/management tasks as one-off processes”

 

Le principe des processus administratifs stipule que les scripts ou les processus tels que les scripts de migration de base de données ou les jobs de population de data, doivent respecter les règles suivantes:

  1. Ces scripts doivent partager le même chemin de déploiement et d’exécution de l’application de base et ne doivent pas être séparés du cycle de vie du développement. Cela signifie que pour une même base de code, on associe une même séquence de Build, Release et Run.
  2. Afin d’éviter tout risque d’interférence avec les processus de production en cas de problème (fail ou potentiel impact de performances), les processus d’administration doivent être exécutés d’une manière séparée et isolés des autres processus de production. Il est préférable de démarrer de nouvelles instances d’exécution.
  3. Une parfaite parité entre les environnements de dev, tests et production permet de valider le bon fonctionnement de ces scripts avant de les appliquer en production.

 

12-Factor App : une base de réflexion

12-Factor App est une méthodologie dont la vocation est d’aider les développeurs dans le développement et le déploiement des applications dites modernes « Cloud native » ou « On-Premises ».

Ces 12 principes se positionnent comme une base de réflexion sur les choix à adopter pour s’offrir des application robustes, scalables et faciles à opérer. La plupart de ces principes sont inspirés des ouvrages de  Martin Flower : « Patterns of Enterprise Application Architecture » et « Refactoring ».

Même si, à première vue, la méthodologie « 12-Factor App » est plus orientée résilience et performance d’applications, elle permet aux développeurs de participer à l’amélioration des processus opérationnels et du Run.

 

Livre blanc Run Cellenza

 

Pour en savoir plus sur le sujet, découvrez notre série d’articles inédits, en partenariat avec Squadra, pour vous aider à mieux appréhender la phase de Run :

Nos autres articles
Commentaires
Laisser un commentaire

Restez au courant des dernières actualités !
Le meilleur de l’actualité sur le Cloud, le DevOps, l’IT directement dans votre boîte mail.