Describes 12-factors, maintainable applications and a small introduction to environment.

This commit is contained in:
Fred Pauchet 2020-09-01 21:52:29 +02:00
parent 7a37981d10
commit 8d8b6c27a3
5 changed files with 32 additions and 32 deletions

View File

@ -14,29 +14,26 @@ L'idée du texte ci-dessous est de jeter les bases d'un bon développement, en s
Ces idées ne s'appliquent pas uniquement à Django et à son cadre de travail, ni même au langage Python. Juste que ces deux bidules sont de bons candidats et que le cadre de travail est bien défini et suffisamment flexible.
Django se présente comme un "Framework Web pour perfectionnistes ayant des deadlines" [https://www.djangoproject.com/].
Django suit link:quelques principes[https://docs.djangoproject.com/en/dev/misc/design-philosophies/].
Django se présente comme un "link:https://www.djangoproject.com/[Framework Web pour perfectionnistes ayant des deadlines]" et suit https://docs.djangoproject.com/en/dev/misc/design-philosophies/[ces quelques principes]:
* Faible couplage et forte cohésion, pour que chaque composant ait son indépendance.
* Moins de code, plus de fonctionnalités.
* link:Don't repeat yourself[https://fr.wikipedia.org/wiki/Sec]: ne pas se répéter!
* https://fr.wikipedia.org/wiki/Ne_vous_r%C3%A9p%C3%A9tez_pas[Don't repeat yourself]: on ne se répète pas !
* Rapidité du développement (après une petite courbe d'apprentissage un peu ardue au début ;-))
Mis côte à côte, l'application de ces principes permet une meilleure stabilité du projet.
Mis côte à côte, l'application de ces principes permet une meilleure stabilité du projet à moyen et long terme. Tout pour plaire à n'importe quel directeur IT.
Dans la première partie, on verra comment configurer l'environnement, comment installer Django de manière isolée et comment démarrer un nouveau projet. On verra comment gérer correctement les dépendances, les versions et comment applique un score sur note code.
On verra aussique la configuration proposée par défaut par le framework n'est pas idéale pour la majorité des cas.
*Dans la première partie*, on verra comment configurer l'environnement, comment installer Django de manière isolée et comment démarrer un nouveau projet. On verra comment gérer correctement les dépendances, les versions et comment appliquer et suivre un score sur note code. On verra aussi que la configuration proposée par défaut par le framework n'est pas idéale dans la majorité des cas.
Pour cela, on présentera différents outils (mypy, flake8, black, ...), la rédaction de tests unitaires et d'intégration pour limiter les régressions, les règles de nomenclature et de contrôle du contenu, ainsi que les bonnes étapes à suivre pour arriver à un déploiement rapide et fonctionnel avec peu d'efforts.
Dans la seconde partie, on détaillera précisément les étapes de déploiement, avec la description et la configuration de l'infrastructure, ainsi que des exemples concrets de déploiement sur deux distributions principales (Debian et CentOS), ainsi que l'utilisation de Docker et Docker-Compose.
*Dans la deuxième partie*, on détaillera précisément les étapes de déploiement, avec la description et la configuration de l'infrastructure, des exemples concrets de déploiement sur deux distributions principales (Debian et CentOS), ainsi que l'utilisation de Docker et Docker-Compose.
On abordera également la supervision et la mise à jour d'une application existante, en respectant les bonnes pratiques d'administration système.
Dans la troisième partie, on abordera les grands principes de modélisation, en suivant les lignes de conduites du cadre de travail. On abordera les concepts clés qui permettent à une application de rester maintenable, les formulaires et leurs validations, les migrations de données et l'administration.
*Dans la troisième partie*, on abordera les grands principes de modélisation, en suivant les lignes de conduites du cadre de travail. On abordera les concepts clés qui permettent à une application de rester maintenable, les formulaires et leurs validations, les migrations de données et l'administration.
Dans la quatrième partie, on mettra ces concepts en pratique en présentant le développement d'une "vraie" application: définition des tables, gestion des utilisateurs, ... et mise à disposition!
*Dans la quatrième partie*, on mettra ces concepts en pratique en présentant le développement d'une "vraie" application: définition des tables, gestion des utilisateurs, ... et mise à disposition!
Et tout ça à un seul et même endroit. Oui. :-)

View File

@ -10,13 +10,15 @@ image::images/django-support-lts.png[]
Ce sera une bonne indication à prendre en considération pour nos dépendances, puisqu'en visant une version particulière, on ne devra pratiquement pas se soucier (bon, un peu quand même...) des dépendances à installer, pour peu qu'on reste sous un certain seuil.
Dans cette partie, on va parler de *méthode de travail*, avec un objectif visé. On peut éviter que l'application ne tourne que sur notre machine et que chaque déploiement ne soit une plaie à gérer. Chaque mise à jour doit se limiter à:
NOTE: en relisant, le passage ci-dessus n'est peut-être pas hyper clair... A refaire.
Dans cette partie, on va parler de *méthode de travail*, avec comme objectif visé, d'éviter que l'application ne tourne que sur notre machine et que chaque déploiement ne soit une plaie à gérer. Chaque mise à jour doit se limiter à:
. démarrer un script,
. prévoir un rollback si cela plante
. se préparer une tisane en regardant nos flux RSS (si cette technologie existe encore...).
**Remarque** : les commandes qui seront exécutés dans ce livre le seront depuis un shell sous GNU/Linux. Certaines devront donc être adaptées si vous êtes dans un autre environnemnet.
**Remarque** : les commandes qui seront exécutés dans ce livre le seront depuis un shell sous GNU/Linux. Certaines devront donc être adaptées si vous êtes dans un autre environnement.
include::12-factors.adoc[]

View File

@ -4,18 +4,19 @@ Pour la méthode de travail et de développement, on va se baser sur les https:/
L'idée derrière cette méthode consiste à pousser les concepts suivants (repris grossièrement de la https://12factor.net/fr/[page d'introduction] :
. Faciliter la mise en place de phases d'automatisation; plus simplement, faciliter les mises à jour applicatives, simplifier la gestion de l'hôte, diminuer la divergence entre les différents environnements d'exécution et offrir la possibilité d'intégrer le projet dans un processus d'https://en.wikipedia.org/wiki/Continuous_integration[intégration continue]/link:https://en.wikipedia.org/wiki/Continuous_deployment[déploiement continu]
. Faciliter la mise à pied de nouveaux développeurs ou de personnes souhaitant rejoindre le projet.
. Faciliter XXX
. Augmenter l'agilité générale du projet, en permettant une meilleure évolutivité architecturale et une meilleure mise à l'échelle - _Vous avez 5000 utilisateurs en plus? Ajoutez un serveur et on n'en parle plus ;-)_.
. *Faciliter la mise en place de phases d'automatisation*; plus concrètement, de faciliter les mises à jour applicatives, simplifier la gestion de l'hôte, diminuer la divergence entre les différents environnements d'exécution et offrir la possibilité d'intégrer le projet dans un processus d'https://en.wikipedia.org/wiki/Continuous_integration[intégration continue]/link:https://en.wikipedia.org/wiki/Continuous_deployment[déploiement continu]
. *Faciliter la mise à pied de nouveaux développeurs ou de personnes souhaitant rejoindre le projet*
. *Minimiser les divergences entre les différents environnemens composant un projet*
. *Augmenter l'agilité générale du projet*, en permettant une meilleure évolutivité architecturale et une meilleure mise à l'échelle - _Vous avez 5000 utilisateurs en plus? Ajoutez un serveur et on n'en parle plus ;-)_.
En pratique, les idées planquées derrière les points ci-dessus permettront de monter facilement un nouvel environnement - qu'il soit sur la machine du petit nouveau dans l'équipe, sur un serveur Azure, Heroku, Digital Ocean ou votre nouveau Raspberry Pi Zéro caché à la cave.
En pratique, les idées qui se trouvent derrière les points ci-dessus permettront de monter facilement un nouvel environnement - qu'il soit sur la machine du petit nouveau dans l'équipe, sur un serveur Azure/Heroku/Digital Ocean ou votre nouveau Raspberry Pi Zéro caché à la cave.
Pour reprendre de manière très brute les différentes idées derrière cette méthode, on a:
. Une base de code suivie par un système de contrôle de versions. Chaque déploiement de l'application devra se baser sur cette source unique, ceci afin de minimiser les différences que l'on pourrait trouver entre un environnement de développement et la mise en production.
NOTE: pensez à retravailler la partie ci-dessous; la version anglophone semble plus compréhensible... :-/
. Une base de code suivie, avec un système de contrôle de versions, signifie plusieurs déploiements
. Déclarez explicitement et isolez les dépendances
. Stockez la configuration dans lenvironnement

View File

@ -15,9 +15,9 @@ Pour tout autre système, vous devriez disposer en natif de ce qu'il faut.
=== Un gestionnaire de base de données
PHPMyAdmin ou PgAdmin. _A priori_, les deux sont disponibles pour tous les systèmes d'exploitation, et sont nativement supportés par Django. Pour SQLite, il existe https://sqlitebrowser.org/[SQLiteBrowser] qui fait très bien le boulot.
PHPMyAdmin ou PgAdmin. _A priori_, les deux sont disponibles pour tous les systèmes d'exploitation, et sont nativement supportés par Django. Pour SQLite, il existe https://sqlitebrowser.org/[SQLiteBrowser] qui fait très bien le boulot. On abordera les <<Bases de données,systèmes de gestion de base de données>>.
Dans tous les cas, le shell Django pourra largement suffire.
Pour tous les autres cas, le shell Django pourra largement suffire.
=== Un gestionnaire de mots de passe
@ -25,4 +25,4 @@ https://keepassxc.org/[KeepassXC]. On en aura besoin pour gé(né)rer des phrase
=== Un système de gestion de versions
https://git-scm.com/[Git]
https://git-scm.com/[Git], pour développer rapidement des preuves de concept, switcher vers une nouvelle fonctionnalité à développer, un bogue à réparer ou une nouvelle release à proposer au téléchargement. Même en développant seul dans son coin, un système de gestion de versions reste indispensable.

View File

@ -7,31 +7,31 @@ Ce livre répartit un ensemble de conseils parmi quatre niveaux de composants:
* Les méthodes et fonctions
* Les classes
* Les composants
* Et de manière plus générale.
* Et des conseils plus généraux.
=== Au niveau des méthodes et fonctions
* Gardez vos méthodes/fonctions courtes. Pas plus de 15 lignes, en comptant les commentaires. Des exceptions sont possibles, mais dans une certaine mesure uniquement (pas plus de 6.9% de plus de 60 lignes; pas plus de 22.3% de plus de 30 lignes, au plus 43.7% de plus de 15 lignes et au moins 56.3% en dessous de 15 lignes). Oui, c'est dur à tenir, mais faisable.
* Conserver une complexité de McCabe en dessous de 5, c'est-à-dire avec quatre branches au maximum. A nouveau, si on a une méthode avec une complexité cyclomatique de 15, la séparer en 3 fonctions avec une complexité de 5 conservera globalement le nombre 15, mais rendra le code de chacune de ces méthodes plus lisible, plus maintenable.
* N'écrivez votre code qu'une seule fois: évitez les duplications, copie, etc., c'est juste mal: imaginez qu'un bug soit découvert dans une fonction; il devra alors être corrigé dans toutes les fonctions qui auront été copiées/collées. C'est aussi une forme de régression.
* Conservez de petites interfaces. Quatre paramètres, pas plus. Au besoin, refactorisez certains paramètres dans une classe, plus facile à tester.
* *Gardez vos méthodes/fonctions courtes*. Pas plus de 15 lignes, en comptant les commentaires. Des exceptions sont possibles, mais dans une certaine mesure uniquement (pas plus de 6.9% de plus de 60 lignes; pas plus de 22.3% de plus de 30 lignes, au plus 43.7% de plus de 15 lignes et au moins 56.3% en dessous de 15 lignes). Oui, c'est dur à tenir, mais faisable.
* *Conserver une complexité de McCabe en dessous de 5*, c'est-à-dire avec quatre branches au maximum. A nouveau, si on a une méthode avec une complexité cyclomatique de 15, la séparer en 3 fonctions avec une complexité de 5 conservera globalement le nombre 15, mais rendra le code de chacune de ces méthodes plus lisible, plus maintenable.
* *N'écrivez votre code qu'une seule fois: évitez les duplications, copie, etc.*, c'est juste mal: imaginez qu'un bug soit découvert dans une fonction; il devra alors être corrigé dans toutes les fonctions qui auront été copiées/collées. C'est aussi une forme de régression.
* *Conservez de petites interfaces*. Quatre paramètres, pas plus. Au besoin, refactorisez certains paramètres dans une classe, plus facile à tester.
=== Au niveau des classes
* Privilégiez un couplage faible entre vos classes. Ceci n'est pas toujours possible, mais dans la mesure du possible, éclatez vos classes en fonction de leur domaine de compétences. L'implémentation du service ``UserNotificationsService`` ne doit pas forcément se trouver embarqué dans une classe ``UserService``. De même, pensez à passer par une interface (commune à plusieurs classes), afin d'ajouter une couche d'abstraction. La classe appellante n'aura alors que les méthodes offertes par l'interface comme points d'entrée.
* *Privilégiez un couplage faible entre vos classes*. Ceci n'est pas toujours possible, mais dans la mesure du possible, éclatez vos classes en fonction de leur domaine de compétences respectif. L'implémentation du service `UserNotificationsService` ne doit pas forcément se trouver embarqué dans une classe `UserService`. De même, pensez à passer par une interface (commune à plusieurs classes), afin d'ajouter une couche d'abstraction. La classe appellante n'aura alors que les méthodes offertes par l'interface comme points d'entrée.
=== Au niveau des composants
* Tout comme pour les classes, il faut conserver un couplage faible au niveau des composants également. Une manière d'arriver à ce résultat est de conserver un nombre de points d'entrée restreint, et d'éviter qu'on ne puisse contacter trop facilement des couches séparées de l'architecture. Pour une architecture n-tiers par exemple, la couche d'abstraction à la base de données ne peut être connue que des services; sans cela, au bout de quelques semaines, n'importe quelle couche de présentation risque de contacter directement la base de données, "juste parce qu'elle en a la possibilité". Vous pourrez également passer par des interfaces, afin de réduire le nombre de points d'entrée connus par un composant externe (qui ne connaîtra par exemple que `IFileTransfer` avec ses méthodes `put` et `get`, et non pas les détails d'implémentation complet d'une classe `FtpFileTransfer` ou `SshFileTransfer`).
* Conserver un bon balancement au niveau des composants: évitez qu'un composant **A** ne soit un énorme mastodonte, alors que le composant juste à côté n'est capable que d'une action. De cette manière, les nouvelles fonctionnalités seront mieux réparties parmi les différents systèmes, et les responsabilités plus faciles à gérer. Un conseil est d'avoir un nombre de composants compris entre 6 et 12 (idéalement, 12), et que ces composants soit approximativement de même taille.
* *Tout comme pour les classes, il faut conserver un couplage faible au niveau des composants* également. Une manière d'arriver à ce résultat est de conserver un nombre de points d'entrée restreint, et d'éviter qu'on ne puisse contacter trop facilement des couches séparées de l'architecture. Pour une architecture n-tiers par exemple, la couche d'abstraction à la base de données ne peut être connue que des services; sans cela, au bout de quelques semaines, n'importe quelle couche de présentation risque de contacter directement la base de données, "juste parce qu'elle en a la possibilité". Vous pourrez également passer par des interfaces, afin de réduire le nombre de points d'entrée connus par un composant externe (qui ne connaîtra par exemple que `IFileTransfer` avec ses méthodes `put` et `get`, et non pas les détails d'implémentation complet d'une classe `FtpFileTransfer` ou `SshFileTransfer`).
* *Conserver un bon balancement au niveau des composants*: évitez qu'un composant **A** ne soit un énorme mastodonte, alors que le composant juste à côté n'est capable que d'une action. De cette manière, les nouvelles fonctionnalités seront mieux réparties parmi les différents systèmes, et les responsabilités plus faciles à gérer. Un conseil est d'avoir un nombre de composants compris entre 6 et 12 (idéalement, 12), et que ces composants soient approximativement de même taille.
=== De manière plus générale
* Conserver une densité de code faible: il n'est évidemment pas possible d'implémenter n'importe quelle nouvelle fonctionnalité en moins de 20 lignes de code; l'idée ici est que la réécriture du projet ne prenne pas plus de 20 hommes/mois. Pour cela, il faut (activement) passer du temps à réduire la taille du code existant: soit en faisant du refactoring (intensif?), soit en utilisant des librairies existantes, soit en explosant un système existant en plusieurs sous-systèmes communiquant entre eux. Mais surtout en évitant de copier/coller bêtement du code existant.
* Automatiser les tests, ajouter un environnement d'intégration continue dès le début du projet et vérifier par des outils les points ci-dessus.
* *Conserver une densité de code faible*: il n'est évidemment pas possible d'implémenter n'importe quelle nouvelle fonctionnalité en moins de 20 lignes de code; l'idée ici est que la réécriture du projet ne prenne pas plus de 20 hommes/mois. Pour cela, il faut (activement) passer du temps à réduire la taille du code existant: soit en faisant du refactoring (intensif?), soit en utilisant des librairies existantes, soit en explosant un système existant en plusieurs sous-systèmes communiquant entre eux. Mais surtout en évitant de copier/coller bêtement du code existant.
* *Automatiser les tests*, *ajouter un environnement d'intégration continue dès le début du projet* et *vérifier par des outils les points ci-dessus*.
=== En pratique
Par rapport aux points repris ci-dessus, l'environnement Python et le framework Django proposent un ensemble d'outils intégrés qui permettent de répondre à chaque point. Avant d'aller plus loin, donc, un petit point sur les conventions, les tests (unitaires, orientés comportement, basés sur la documentation, ...), la gestion de version du code et sur la documentation. Plus que dans tout langage compilé, ceux-ci sont pratiquement obligatoires. Vous pourrez les voir comme une perte de temps dans un premier temps, mais nous vous promettons qu'ils vous en feront gagner par la suite.
Par rapport aux points repris ci-dessus, l'environnement Python et le framework Django proposent un ensemble d'outils intégrés qui permettent de répondre à chaque point. Avant d'aller plus loin, donc, un petit point sur les conventions, les tests (unitaires, orientés comportement, basés sur la documentation, ...), la gestion de version du code, le typage de paramètre et de valeurs de retour et sur la documentation. Plus que dans tout langage compilé, ceux-ci sont pratiquement obligatoires. Vous pourrez les voir comme une perte de temps dans un premier temps, mais nous vous promettons qu'ils vous en feront gagner par la suite.
NOTE: parlez des principes SOLID