... to \ldots
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Fred Pauchet 2022-05-11 20:01:39 +02:00
parent bc7c7f74d4
commit ad625a1b40
16 changed files with 141 additions and 144 deletions

View File

@ -289,7 +289,4 @@ class PeopleSerializer(serializers.HyperlinkedModelSerializer):
\end{minted}
Nous ne faisons donc bien que redéfinir la propriété
\texttt{contract\_set} et indiquons qu'il s'agit à présent d'une
instance de \texttt{ContractSerializer}, et qu'il est possible d'en
avoir plusieurs. C'est tout.
Nous ne faisons donc bien que redéfinir la propriété \texttt{contract\_set} et indiquons qu'il s'agit à présent d'une instance de \texttt{ContractSerializer}, et qu'il est possible d'en avoir plusieurs. C'est tout.

View File

@ -98,7 +98,7 @@ Une méthode \texttt{render} permet également de proposer (très grossièrement
\end{listing}
Lorsque nous devrons ajouter un nouveau rendu (Atom, OpenXML, ...), il sera nécessaire de modifier la classe \texttt{Document}.
Lorsque nous devrons ajouter un nouveau rendu (Atom, OpenXML, \ldots) il sera nécessaire de modifier la classe \texttt{Document}.
Ceci n'est:
\begin{enumerate}
@ -143,7 +143,7 @@ En suivant le principe de responsabilité unique, une bonne pratique consiste à
A présent, lorsque nous devrons ajouter un nouveau format de prise en charge, il nous suffira de modifier la classe \texttt{DocumentRenderer}, sans que la classe \texttt{Document} ne soit impactée.
En même temps, le jour où une instance de type \texttt{Document} sera liée à un champ \texttt{author}, rien ne dit que le rendu devra en tenir compte; nous modifierons donc notre classe pour y ajouter le nouveau champ sans que cela n'impacte nos différentes manières d'effectuer un rendu.
Un autre exemple consiterait à faire communiquer une méthode avec une base de données: ce ne sera pas à cette méthode à gérer l'inscription d'une exception à un emplacement spécifique (emplacement sur un disque, ...): cette action doit être prise en compte par une autre classe (ou un autre concept ou composant), qui s'occupera de définir elle-même l'emplacement où l'évènement sera enregistré, que ce soit dans une base de données, une instance Graylog ou un fichier.
Un autre exemple consiterait à faire communiquer une méthode avec une base de données: ce ne sera pas à cette méthode à gérer l'inscription d'une exception à un emplacement spécifique (emplacement sur un disque, \ldots): cette action doit être prise en compte par une autre classe (ou un autre concept ou composant), qui s'occupera de définir elle-même l'emplacement où l'évènement sera enregistré, que ce soit dans une base de données, une instance Graylog ou un fichier.
Cette manière de structurer le code permet de centraliser la configuration d'un type d'évènement à un seul endroit, ce qui augmente ainsi la testabilité globale du projet.
L'équivalent du principe de responsabilité unique au niveau des composants sera le \texttt{Common Closure Principle} \index{CCP}.
@ -335,7 +335,7 @@ Petit exemple pratique: si nous définissons une méthode \texttt{make\_some\_no
def make_some_noise(self):
print("Roaaar!")
\end{minted}
\caption{Un lion et un canard sont sur un bateau...}
\caption{Un lion et un canard sont sur un bateau\ldots}
\end{listing}
Le principe de substitution de Liskov suggère qu'une classe doit toujours pouvoir être considérée comme une instance de sa classe parente, et \textbf{doit pouvoir s'y substituer}.
@ -365,7 +365,7 @@ Pour revenir à nos exemples de rendus de documents, nous aurions pu faire héri
import markdown
return markdown.markdown(document.content)
\end{minted}
\caption{Le convertisseur Markdown hérite d'un convertisseur XML...}
\caption{Le convertisseur Markdown hérite d'un convertisseur XML\ldots}
\end{listing}
Si nous décidons à un moment d'ajouter une méthode d'entête au niveau de notre classe de rendu XML, notre rendu en Markdown héritera irrémédiablement de cette même méthode:
@ -397,7 +397,7 @@ Si nous décidons à un moment d'ajouter une méthode d'entête au niveau de not
\caption{\ldots~ et il a mal à l'entête}
\end{listing}
Le code ci-dessus ne porte pas à conséquence \footnote{Pas immédiatement, en tout cas...}, mais dès que nous invoquerons la méthode \texttt{header()} sur une instance de type \texttt{MarkdownRenderer}, nous obtiendrons un bloc de déclaration XML (\texttt{\textless{}?xml\ version\ =\ "1.0"?\textgreater{}}) pour un fichier Markdown, ce qui n'aura aucun sens.
Le code ci-dessus ne porte pas à conséquence \footnote{Pas immédiatement, en tout cas\ldots}, mais dès que nous invoquerons la méthode \texttt{header()} sur une instance de type \texttt{MarkdownRenderer}, nous obtiendrons un bloc de déclaration XML (\texttt{\textless{}?xml\ version\ =\ "1.0"?\textgreater{}}) pour un fichier Markdown, ce qui n'aura aucun sens.
En revenant à notre proposition d'implémentation, suite au respect d'Open-Closed, une solution serait de n'implémenter la méthode \texttt{header()} qu'au niveau de la classe \texttt{XmlRenderer}:
@ -551,7 +551,7 @@ Lobjectif est donc de découpler ces différentes fonctionnalités en plusieu
\end{listing}
Cette réflexion s'applique à n'importe quel composant: votre système d'exploitation, les librairies et dépendances tierces, les variables déclarées, ...
Cette réflexion s'applique à n'importe quel composant: votre système d'exploitation, les librairies et dépendances tierces, les variables déclarées, \ldots
Quel que soit le composant que l'on utilise ou analyse, il est plus qu'intéressant de se limiter uniquement à ce dont nous avons besoin plutôt que d'embarquer le must absolu qui peut faire 1000x fonctions de plus que n'importe quel autre produit, alors que seules deux d'entre elles seront nécessaires.
En Python, ce comportement est inféré lors de l'exécution, et donc pas vraiment d'application pour ce contexte d'étude: de manière plus générale, les langages dynamiques sont plus flexibles et moins couplés que les langages statiquement typés, pour lesquels l'application de ce principe-ci permettrait de juste mettre à jour une DLL ou un JAR sans que cela n'ait d'impact sur le reste de l'application.

View File

@ -2,4 +2,4 @@
\section{Waffle}
\section{...}
\section{\ldots}

View File

@ -94,7 +94,7 @@ Cela permet de valider des données reçues en entrée et d'afficher (très) fac
Par contre, c'est lourd.
Dès qu'on souhaite peaufiner un peu l'affichage, contrôler parfaitement ce que l'utilisateur doit remplir,
modifier les types de contrôleurs, les placer au pixel près, ...
modifier les types de contrôleurs, les placer au pixel près, \ldots
Tout ça demande énormément de temps.
Et c'est là qu'intervient \href{http://django-crispy-forms.readthedocs.io/en/latest/}{Django-Crispy-Forms}.
Cette librairie intègre plusieurs frameworks CSS (Bootstrap, Foundation et uni-form) et permet de contrôler entièrement le \textbf{layout} et la présentation.
@ -118,5 +118,5 @@ Pour chaque champ, crispy-forms va :
\section{Conclusions}
Toute donnée entrée par l'utilisateur, quelle qu'elle soit, \textbf{doit} passer par une instance de \texttt{form}: qu'il s'agisse d'un formulaire HTML, d'un fichier CSV, d'un parser XML, ...
Toute donnée entrée par l'utilisateur, quelle qu'elle soit, \textbf{doit} passer par une instance de \texttt{form}: qu'il s'agisse d'un formulaire HTML, d'un fichier CSV, d'un parser XML, \ldots
Dès que des informations "de l'extérieur" font mine d'arriver dans le périmètre de votre application, il convient d'appliquer immédiatement des principes de sécurité reconnus.

View File

@ -52,7 +52,7 @@ Il s'agit des composants comme le proxy inverse ou les distributeurs de charge:
\begin{quote}
Focusing on resilience often means that a firm can handle events that may cause crises for most organizations in a manner that is routine and mundane.
Specific architectural patterns that they implemented included fail fasts (settings aggressive timeouts such that failing components don't make the entire system crawl to a halt), fallbacks (designing each feature to degrade or fall back to a lower quality representation), and feature removal (removing non-critical features when they run slowly from any given page to prevent them from impacting the member experience).
Another astonishing example of the resilience that the netflix team created beyond preserving business continuity during the AWS outage, was that they went over six hours into the AWS outage before declaring a Sev 1 incident, assuming that AWS service would eventually be restored (i.e., "AWS will come back... it usually does, right ?").
Another astonishing example of the resilience that the netflix team created beyond preserving business continuity during the AWS outage, was that they went over six hours into the AWS outage before declaring a Sev 1 incident, assuming that AWS service would eventually be restored (i.e., "AWS will come back\ldots it usually does, right ?").
Only after six hours into the outage did they activate any business continuity procedures. \cite[p. 282]{devops_handbook}
\end{quote}
@ -153,7 +153,7 @@ L'analyse de ces métriques garantit un juste retour d'informations, sous réser
La première étape consiste à agréger ces données dans un dépôt centralisé, tandis que la seconde étape exigera une structuration correcte des données envoyées.
La collecte des données doit récupérer des données des couches métiers, applicatives et d'environnement.
Ces données couvrent les évènements, les journaux et les métriques - indépendamment de leur source - le pourcentage d'utilisation du processeur, la mémoire utilisée, les disques systèmes, l'utilisation du réseau, ...
Ces données couvrent les évènements, les journaux et les métriques - indépendamment de leur source - le pourcentage d'utilisation du processeur, la mémoire utilisée, les disques systèmes, l'utilisation du réseau, \ldots
\begin{enumerate}
\item
@ -204,7 +204,7 @@ Chaque évènement est associé à un niveau; celui-ci indique sa criticité et
\textbf{DEBUG}: Il s'agit des informations qui concernent tout ce qui peut se passer durant l'exécution de l'application.
Généralement, ce niveau est désactivé pour une application qui passe en production, sauf s'il est nécessaire d'isoler un comportement en particulier, auquel cas il suffit de le réactiver temporairement.
\item
\textbf{INFO}: Enregistre les actions pilotées par un utilisateur - Démarrage de la transaction de paiement, ...
\textbf{INFO}: Enregistre les actions pilotées par un utilisateur - Démarrage de la transaction de paiement, \ldots
\item
\textbf{WARN}: Regroupe les informations qui pourraient potentiellement devenir des erreurs.
\item
@ -262,7 +262,7 @@ exemples}.
Il existe également \href{https://munin-monitoring.org}{Munin}, \href{https://www.elastic.co}{Logstash, ElasticSearch et Kibana (ELK-Stack)} ou \href{https://www.fluentd.org}{Fluentd}.
\subsubsection{Zabbix, Nagios, ...}
\subsubsection{Zabbix, Nagios, \ldots}
\subsubsection{Sentry}

View File

@ -1,3 +1,3 @@
\chapter{Kubernetes}
Voir ici https://www.youtube.com/watch?v=NAOsLaB6Lfc ( La vidéo dure 5h... )
Voir ici https://www.youtube.com/watch?v=NAOsLaB6Lfc ( La vidéo dure 5h\ldots )

View File

@ -73,7 +73,7 @@ Ce dépôt n'est pas uniquement destiné à hébergé le code source, mais égal
Chaque installation ou configuration doit toujours être faite de la même manière, et doit pouvoir être répétée quel que soit l'environnement cible.
Ceci permet d'éviter que l'application n'utilise une dépendance qui ne soit déjà installée sur un des sytèmes de développement, et qu'elle soit difficile, voire impossible, à répercuter sur un autre environnement.
Dans le cas de Python, cela pourra être fait au travers de \href{https://pypi.org/project/pip/}{PIP - Package Installer for Python} ou \href{https://python-poetry.org/}{Poetry}.
La majorité des langages moderners proposent des mécanismes similaires (\href{https://rubygems.org/}{Gem} pour Ruby, \href{https://www.npmjs.com/}{NPM} pour NodeJS, ...)
La majorité des langages moderners proposent des mécanismes similaires (\href{https://rubygems.org/}{Gem} pour Ruby, \href{https://www.npmjs.com/}{NPM} pour NodeJS, \ldots)
Dans tous les cas, chaque application doit disposer d'un environnement sain, qui lui est assigné. Vu le peu de ressources que cela coûte, il ne faut pas s'en priver.
Chaque dépendance devra déclarer et épingler dans un fichier la version nécessaire.
@ -95,11 +95,11 @@ que:
\item \ldots
\end{enumerate}
En pratique, toute information susceptible d'évoluer ou de changer (un seuil, une ressource externe, un couple utilisateur/mot de passe, ...) doit se trouver dans un fichier ou dans une variable d'environnement, et doit être facilement modifiable.
En pratique, toute information susceptible d'évoluer ou de changer (un seuil, une ressource externe, un couple utilisateur/mot de passe, \ldots) doit se trouver dans un fichier ou dans une variable d'environnement, et doit être facilement modifiable.
Ceci permet de paramétrer facilement un environnement (par exemple, un container), simplement en modifiant une variable de configuration qui spécifierait la base de données sur laquelle l'application devra se connecter.
Toute clé de configuration (nom du serveur de base de données, adresse d'un service Web externe, clé d'API pour l'interrogation d'une ressource, ...) sera définie directement au niveau de l'hôte - à aucun moment, nous ne devons trouver un mot de passe en clair dans le dépôt source ou une valeur susceptible d'évoluer, écrite en dur dans le code. \footnote{Ainsi, nous pourrions faire une \href{https://github.com/search?q=filenamefilename:.env DB_USERNAME&type=Code}{recherche sur Github} pour retrouver certaines variables d'environnement qui auraient été laissées en dur dans le code source de certains projets. Le \href{https://github.com/techgaun/github-dorks}{dépôt suivant} liste quelques idées de variables à rechercher...}.
Toute clé de configuration (nom du serveur de base de données, adresse d'un service Web externe, clé d'API pour l'interrogation d'une ressource, \ldots) sera définie directement au niveau de l'hôte - à aucun moment, nous ne devons trouver un mot de passe en clair dans le dépôt source ou une valeur susceptible d'évoluer, écrite en dur dans le code. \footnote{Ainsi, nous pourrions faire une \href{https://github.com/search?q=filenamefilename:.env DB_USERNAME&type=Code}{recherche sur Github} pour retrouver certaines variables d'environnement qui auraient été laissées en dur dans le code source de certains projets. Le \href{https://github.com/techgaun/github-dorks}{dépôt suivant} liste quelques idées de variables à rechercher\ldots}.
Au moment de développer une nouvelle fonctionnalité, réfléchissez si
l'un des paramètres utilisés risquerait de subir une modification ou s'il concerne un principe de sécurité: ce composant peut concerner une nouvelle chaîne de connexion, un point de terminaison nécessaire à télécharger des données officielles ou un chemin vers un répertoire partagé pour y déposer un fichier.
@ -109,13 +109,13 @@ Par exemple, Gitea expose \href{https://docs.gitea.io/en-us/config-cheat-sheet/}
\section{Ressources externes}
Nous parlons de bases de données, de services de mise en cache, d'API externes, ... L'application doit être capable d'effectuer des changements au niveau de ces ressources sans que son code ne soit modifié.
Nous parlons de bases de données, de services de mise en cache, d'API externes, \ldots L'application doit être capable d'effectuer des changements au niveau de ces ressources sans que son code ne soit modifié.
Nous parlons alors de \textbf{ressources attachées}, dont la présence est nécessaire au bon fonctionnement de l'application, mais pour lesquelles le \textbf{type} n'est pas obligatoirement défini.
Nous voulons par exemple "une base de données" et "une mémoire cache", et pas "une base MariaDB et une instance Memcached".
De cette manière, les ressources peuvent être attachées et détachées d'un déploiement à la volée.
Si une base de données ne fonctionne pas correctement (problème matériel ?), l'administrateur pourrait simplement restaurer un nouveau serveur à partir d'une précédente sauvegarde, et l'attacher à l'application sans que le code source ne soit modifié. une solution consiste à passer toutes ces informations (nom du serveur et type de base de données, clé d'authentification, ... directement \emph{via} des variables d'environnement.
Si une base de données ne fonctionne pas correctement (problème matériel ?), l'administrateur pourrait simplement restaurer un nouveau serveur à partir d'une précédente sauvegarde, et l'attacher à l'application sans que le code source ne soit modifié. une solution consiste à passer toutes ces informations (nom du serveur et type de base de données, clé d'authentification, \ldots directement \emph{via} des variables d'environnement.
\includegraphics{images/12factors/attached-resources.png}
@ -140,7 +140,7 @@ Ces ressources sont donc spécifiés grâce à des variables d'environnement, et
\includegraphics{images/12factors/release.png}
Parmi les solutions possibles, nous pourrions nous pourrions nous baser
sur les \emph{releases} de Gitea, sur un serveur d'artefacts (\href{https://fr.wikipedia.org/wiki/Capistrano_(logiciel)}{Capistrano}), voire directement au niveau de forge logicielle (Gitea, Github, Gitlab, ...).
sur les \emph{releases} de Gitea, sur un serveur d'artefacts (\href{https://fr.wikipedia.org/wiki/Capistrano_(logiciel)}{Capistrano}), voire directement au niveau de forge logicielle (Gitea, Github, Gitlab, \ldots).
\section{Mémoire des processus d'exécution}
@ -168,7 +168,7 @@ Le serveur (= l'hôte) choisit d'appliquer une correspondance entre "son" port 4
\section{Connaissance et confiance des processus systèmes}
Comme décrit plus haut (cf. \#6), l'application doit utiliser des processus \emph{stateless} (sans état). Nous pouvons créer et utiliser des processus supplémentaires pour tenir plus facilement une lourde charge, ou dédier des particuliers pour certaines tâches: requêtes HTTP \emph{via} des processus Web; \emph{long-running} jobs pour des processus asynchrones, ...
Comme décrit plus haut (cf. \#6), l'application doit utiliser des processus \emph{stateless} (sans état). Nous pouvons créer et utiliser des processus supplémentaires pour tenir plus facilement une lourde charge, ou dédier des particuliers pour certaines tâches: requêtes HTTP \emph{via} des processus Web; \emph{long-running} jobs pour des processus asynchrones, \ldots
Si cela existe sur l'hôte hébergeant l'application, ne vous fatiguez pas: utilisez le.
\includegraphics{images/12factors/process-types.png}

View File

@ -195,9 +195,9 @@ class Migration(migrations.Migration):
\begin{itemize}
\item
La migration supprime l'ancienne clé étrangère ...
La migration supprime l'ancienne clé étrangère \ldots
\item
... et ajoute une nouvelle table, permettant de lier nos catégories à nos livres.
\ldots et ajoute une nouvelle table, permettant de lier nos catégories à nos livres.
\end{itemize}
\includegraphics{images/db/migrations-0002-many-to-many.png}
@ -517,5 +517,5 @@ En résumé:
\begin{enumerate}
\item Soit on supprime toutes les migrations (en conservant le fichier \texttt{\_\_init\_\_.py})
\item Soit on réinitialise proprement les migrations avec un \texttt{--fake-initial} (sous réserve que toutes les personnes qui utilisent déjà le projet s'y conforment... Ce qui n'est pas gagné.
\item Soit on réinitialise proprement les migrations avec un \texttt{--fake-initial} (sous réserve que toutes les personnes qui utilisent déjà le projet s'y conforment\ldots Ce qui n'est pas gagné.
\end{enumerate}

View File

@ -146,7 +146,7 @@ Nous arrivons alors à un modèle hybride, mélangeant des structures de donnée
Lors de l'analyse d'une classe de modèle, nous pouvons voir que Django exige un héritage de la classe \texttt{django.db.models.Model}.
Nous pouvons regarder les propriétés définies dans cette classe en analysant le fichier
\texttt{lib\textbackslash{}site-packages\textbackslash{}django\textbackslash{}models\textbackslash{}base.py}.
Outre que \texttt{models.Model} hérite de \texttt{ModelBase} au travers de \href{https://pypi.python.org/pypi/six}{six} pour la rétrocompatibilité vers Python 2.7, cet héritage apporte notamment les fonctions \texttt{save()}, \texttt{clean()}, \texttt{delete()}, ...
Outre que \texttt{models.Model} hérite de \texttt{ModelBase} au travers de \href{https://pypi.python.org/pypi/six}{six} pour la rétrocompatibilité vers Python 2.7, cet héritage apporte notamment les fonctions \texttt{save()}, \texttt{clean()}, \texttt{delete()}, \ldots
En résumé, toutes les méthodes qui font qu'une instance sait \textbf{comment} interagir avec la base de données.
\section{Types de champs, relations et clés étrangères}
@ -251,7 +251,7 @@ Le \texttt{shell} est un environnement REPL \index{REPL} identique à ce que l'i
\item Voire, exceptionnellement, d'analyser un soucis en production.
\end{enumerate}
Il se démarre grâce à la commande \texttt{python manage.py shell}, et donne un accès intuitif \footnote{Pour un développeur...} à l'ensemble des informations disponibles.
Il se démarre grâce à la commande \texttt{python manage.py shell}, et donne un accès intuitif \footnote{Pour un développeur\ldots} à l'ensemble des informations disponibles.
\subsection{Accès aux relations}
@ -361,7 +361,7 @@ Ca, c'est le deuxième niveau. Le contexte donne accès à déjà plus d'informa
raise ValidationError('Title does not start with T')
\end{minted}
Il n'est plus nécessaire de définir d'attribut \texttt{validators=[...]}, puisque Django va appliquer un peu d'introspection pour récupérer toutes les méthodes qui commencent par \texttt{clean\_} et pour les faire correspondre au nom du champ à valider (ici, \texttt{title}).
Il n'est plus nécessaire de définir d'attribut \texttt{validators=[\ldots]}, puisque Django va appliquer un peu d'introspection pour récupérer toutes les méthodes qui commencent par \texttt{clean\_} et pour les faire correspondre au nom du champ à valider (ici, \texttt{title}).
\subsection{Clean}
@ -386,13 +386,13 @@ class ItemManager(...):
\section{Jointures, compositions et filtres}
Pour appliquer une jointure sur un modèle, nous pouvons passer par les méthodes \texttt{select\_related} et \texttt{prefetch\_related}.
Il faut cependant faire \textbf{très} attention au prefetch related, qui fonctionne en fait comme une grosse requête dans laquelle nous trouvons un \texttt{IN\ (...)}.
Il faut cependant faire \textbf{très} attention au prefetch related, qui fonctionne en fait comme une grosse requête dans laquelle nous trouvons un \texttt{IN\ (\ldots)}.
Càd que Django va récupérer tous les objets demandés initialement par le queryset, pour ensuite prendre
toutes les clés primaires, pour finalement faire une deuxième requête et récupérer les relations externes.
Au final, si votre premier queryset est relativement grand (nous parlons de 1000 à 2000 éléments, en fonction du moteur de base de données), la seconde requête va planter et vous obtiendrez une exception de type \texttt{django.db.utils.OperationalError:\ too\ many\ SQL\ variables}.
Nous pourrions penser qu'utiliser un itérateur permettrait de combiner les deux, mais ce n'est pas le cas...
Nous pourrions penser qu'utiliser un itérateur permettrait de combiner les deux, mais ce n'est pas le cas\ldots
Comme l'indique la documentation:

View File

@ -117,10 +117,10 @@ Nous faisons ici une distinction entre un \textbf{projet} et une \textbf{applica
\begin{itemize}
\item
\textbf{Un projet} représente l'ensemble des applications, paramètres, middlewares, dépendances, ..., qui font que votre code fait ce qu'il est sensé faire.
\textbf{Un projet} représente l'ensemble des applications, paramètres, middlewares, dépendances, \ldots, qui font que votre code fait ce qu'il est sensé faire.
Il s'agit grosso modo d'un câblage de tous les composants entre eux.
\item
\textbf{Une application} est un contexte d'exécution (vues, comportements, pages HTML, ...), idéalement autonome, d'une partie du projet.
\textbf{Une application} est un contexte d'exécution (vues, comportements, pages HTML, \ldots), idéalement autonome, d'une partie du projet.
Une application est supposée avoir une portée de réutilisation, même s'il ne sera pas toujours possible de viser une généricité parfaite.
\end{itemize}
@ -155,7 +155,7 @@ En rouge, vous pouvez voir quelque chose que nous avons déjà vu: la gestion de
Ceci pourrait être commun aux deux projets.
Nous pouvons clairement visualiser le principe de \textbf{contexte} pour une application: celle-ci viendra avec son modèle, ses tests, ses vues et son paramétrage et pourrait ainsi être réutilisée dans un autre projet.
C'est en ça que consistent les \href{https://www.djangopackages.com/}{paquets Django} déjà disponibles:
ce sont "\emph{simplement}" de petites applications empaquetées et pouvant être réutilisées dans différents contextes (eg. \href{https://github.com/tomchristie/django-rest-framework}{Django-Rest-Framework}, \href{https://github.com/django-debug-toolbar/django-debug-toolbar}{Django-Debug-Toolbar}, ...
ce sont "\emph{simplement}" de petites applications empaquetées et pouvant être réutilisées dans différents contextes (eg. \href{https://github.com/tomchristie/django-rest-framework}{Django-Rest-Framework}, \href{https://github.com/django-debug-toolbar/django-debug-toolbar}{Django-Debug-Toolbar}, \ldots
Le projet s'occupe principalement d'appliquer une couche de glue entre différentes applications.
@ -186,7 +186,7 @@ catégories:
\item
\textbf{auth}: création d'un nouveau super-utilisateur, changer le mot de passe pour un utilisateur existant.
\item
\textbf{django}: vérifier la \textbf{conformité} du projet, lancer un \textbf{shell}, \textbf{dumper} les données de la base, effectuer une migration du schéma, ...
\textbf{django}: vérifier la \textbf{conformité} du projet, lancer un \textbf{shell}, \textbf{dumper} les données de la base, effectuer une migration du schéma, \ldots
Ce sont des commandes d'administration générale.
\item
\textbf{sessions}: suppressions des sessions en cours
@ -264,12 +264,12 @@ La structure de vos répertoires devient celle-ci:
TODO
Notre application a bien été créée, et nous l'avons déplacée dans le répertoire \texttt{gwift} ! \footnote{Il manque quelques fichiers utiles, qui seront décrits par la suite, pour qu'une application soit réellement autonome: templates, \texttt{urls.py}, managers, services, ...}
Notre application a bien été créée, et nous l'avons déplacée dans le répertoire \texttt{gwift} ! \footnote{Il manque quelques fichiers utiles, qui seront décrits par la suite, pour qu'une application soit réellement autonome: templates, \texttt{urls.py}, managers, services, \ldots}
\section{Fonctionnement général}
Le métier de programmeur est devenu de plus en plus complexe.
Il y a 20 ans, nous pouvions nous contenter d'une simple page PHP dans laquelle nous mixions l'ensemble des actions à réaliser : requêtes en bases de données, construction de la page, ...
Il y a 20 ans, nous pouvions nous contenter d'une simple page PHP dans laquelle nous mixions l'ensemble des actions à réaliser : requêtes en bases de données, construction de la page, \ldots
La recherche d'une solution à un problème n'était pas spécialement plus complexe - dans la mesure où le rendu des enregistrements en direct n'était finalement qu'une forme un chouia plus évoluée du \texttt{print()} ou des \texttt{System.out.println()} - mais c'était l'évolutivité des applications qui en prenait un coup: une grosse partie des tâches étaient dupliquées entre les différentes pages, et l'ajout d'une nouvelle fonctionnalité était relativement ardue.
Django (et d'autres frameworks) résolvent ce problème en se basant ouvertement sur le principe de \texttt{Dont\ repeat\ yourself} \footnote{DRY}.
@ -402,7 +402,7 @@ TODO : passer à poetry
\subsection{Cookie-cutter}
Pfiou! Ca en fait des commandes et du boulot pour "juste" démarrer un nouveau projet, non? Sachant qu'en plus, nous avons dû modifier des fichiers, déplacer des dossiers, ajouter des dépendances, configurer une
base de données, ...
base de données, \ldots
Bonne nouvelle! Il existe des générateurs, permettant de démarrer rapidement un nouveau projet sans (trop) se prendre la tête.
Le plus connu (et le plus personnalisable) est \href{https://cookiecutter.readthedocs.io/}{Cookie-Cutter}, qui se base sur des canevas \emph{type \href{https://pypi.org/project/Jinja2/}{Jinja2}}, pour créer une
@ -468,7 +468,7 @@ On a deux choix ici:
\subsection{Couverture de code}
Quel que soit le framework de tests choisi (django-tests, pytest, unittest, ...), la couverture de code est une analyse qui donne un pourcentage lié à la quantité de code couvert par les tests.
Quel que soit le framework de tests choisi (django-tests, pytest, unittest, \ldots), la couverture de code est une analyse qui donne un pourcentage lié à la quantité de code couvert par les tests.
Il ne s'agit pas de vérifier que le code est bien testé, mais de vérifier quelle partie du code est testée.
Le paquet coverage se charge dévaluer le pourcentage de code couvert par les tests.
Avec pytest, il convient dutiliser le paquet pytest-cov, suivi de la commande pytest

View File

@ -783,4 +783,4 @@ facteurs → Construction du fichier setup.cfg
django_coverage_plugin
\end{verbatim}
Mypy + black + pylint + flake8 + pyflakes + ...
Mypy + black + pylint + flake8 + pyflakes + \ldots

View File

@ -22,7 +22,7 @@ Notre première vue permettra de récupérer la liste des objets de type \texttt
Supposez que cette liste soit accessible \textit{via} la clé \texttt{wishlists} d'un dictionnaire passé au template.
Cette liste devient dès lors accessible grâce aux tags \texttt{\{\% for wishlist in wishlists \%\}}.
A chaque tour de boucle, nous pourrons directement accéder à la variable \texttt{\{\{ wishlist \}\}}.
De même, il sera possible d'accéder aux propriétés de cette objet de la même manière: \texttt{\{\{ wishlist.id \}\}}, \texttt{\{\{ wishlist.description \}\}}, ... et d'ainsi respecter la mise en page que nous souhaitons.
De même, il sera possible d'accéder aux propriétés de cette objet de la même manière: \texttt{\{\{ wishlist.id \}\}}, \texttt{\{\{ wishlist.description \}\}}, \ldots et d'ainsi respecter la mise en page que nous souhaitons.
En reprenant l'exemple de la page HTML définie ci-dessus, nous pouvons l'agrémenter de la manière suivante:

View File

@ -175,7 +175,7 @@ indépendamment des autres. \cite{clean_code}
Le plus important est de toujours corréler les phases de tests indépendantes du reste du travail (de développement, ici), en lautomatisant au plus près de sa source de création:
\begin{quote}
Martin Fowler observes that, in general, "a ten minute build [and test process] is perfectly within reason...
Martin Fowler observes that, in general, "a ten minute build [and test process] is perfectly within reason\ldots
[We first] do the compilation and run tests that are more localized unit tests with the database completely stubbed out. Such tests can run very fast, keeping within the ten minutes guideline.
However any bugs that involve larger scale intercations, particularly those involving the real database, wont be found.
The second stage build runs a different suite of tests [acceptance tests] that do hit the real database and involve more end-to-end behavior.
@ -204,7 +204,7 @@ Certains recommandent de le garder sous une complexité de 10; d'autres de 5.
Idéalement, chaque fonction ou méthode doit être testée afin de bien en valider le fonctionnement, indépendamment du reste des composants.
Cela permet d'isoler chaque bloc de manière unitaire, et permet de ne pas rencontrer de régression lors de l'ajout d'une nouvelle fonctionnalité ou de la modification d'une existante.
Il existe plusieurs types de tests (intégration, comportement, ...)
Il existe plusieurs types de tests (intégration, comportement, \ldots)
Avoir des tests, c'est bien.
S'assurer que tout est testé, c'est mieux.
@ -220,7 +220,7 @@ Le paquet \texttt{coverage} se charge d'évaluer le pourcentage de code couvert
what the customer meant it to.
\end{quote}
Les tests dacceptance vérifient que lapplication fonctionne comme convenu, mais à un plus haut niveau (fonctionnement correct dune API, validation dune chaîne dactions effectuées par un humain, ...).
Les tests dacceptance vérifient que lapplication fonctionne comme convenu, mais à un plus haut niveau (fonctionnement correct dune API, validation dune chaîne dactions effectuées par un humain, \ldots).
\subsection{Tests d'intégration}

View File

@ -263,7 +263,7 @@ Ce qui est quand même 'achement plus simple que d'appréhender tout un
\section{Un système de virtualisation}
Par "\emph{système de virtualisation}", nous entendons n'importe quel application, système d'exploitation, système de containeurisation, ... qui permette de créer ou recréer un environnement de développement aussi proche que celui en production.
Par "\emph{système de virtualisation}", nous entendons n'importe quel application, système d'exploitation, système de containeurisation, \ldots qui permette de créer ou recréer un environnement de développement aussi proche que celui en production.
Les solutions sont nombreuses:
\begin{itemize}

View File

@ -122,7 +122,7 @@ Quelques remarques:
En fonction de vos affinités, vous pourriez également passer par `PluCSS <http://plucss.pluxml.org/>`_, `Pure <http://purecss.io/>`_, `Knacss <http://knacss.com/>`_, `Cascade <http://www.cascade-framework.com/>`_, `Semantic <http://semantic-ui.com/>`_ ou `Skeleton <http://getskeleton.com/>`_. Pour notre plus grand bonheur, les frameworks de ce type pullulent. Reste à choisir le bon.
*A priori*, si vous relancez le serveur de développement maintenant, vous devriez déjà voir les modifications... Mais pas les images, ni tout autre fichier statique.
*A priori*, si vous relancez le serveur de développement maintenant, vous devriez déjà voir les modifications\ldots Mais pas les images, ni tout autre fichier statique.
==== Fichiers statiques

View File

@ -44,7 +44,7 @@ Le serveur que Django met à notre disposition \emph{via} la commande \texttt{ru
En production:
\begin{itemize}
\item Il est inutile de passer par du code Python pour charger des fichiers statiques (feuilles de style, fichiers JavaScript, images, ...
\item Il est inutile de passer par du code Python pour charger des fichiers statiques (feuilles de style, fichiers JavaScript, images, \ldots
De même, Django propose par défaut une base de données SQLite, qui fonctionne parfaitement dès lors que l'on connait ses limites et que l'on se limite à un utilisateur à la fois.
\item Il est légitime que la base de donnée soit capable de supporter plusieurs utilisateurs et connexions simultanés.
En restant avec les paramètres par défaut, il est plus que probable que vous rencontriez rapidement des erreurs de verrou parce qu'un autre processus a déjà pris la main pour écrire ses données. En bref, vous avez quelque chose qui fonctionne, qui répond à un besoin, mais qui va attirer la grogne de ses utilisateurs pour des problèmes de latences, pour des erreurs de verrou ou simplement parce que le serveur répondra trop lentement.