Add appendices
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Fred Pauchet 2022-05-31 20:39:48 +02:00
parent 9e8b04ef5e
commit 0c2aeee91e
8 changed files with 125 additions and 68 deletions

View File

@ -1,19 +1,27 @@
\chapter{Infrastructure et composants}
Deux types d'applications peuvent être considérées: les applications consommant intensivement des données (\textit{Data-intensive applications}) et les applications consommant principalement des cycles processeur (\textit{Compute-intensive applications}).
Une application consommant principalement des données est rarement limitée par la puisse du CPU, mais plus souvent par la quantité et la complexité des structures de données, et la vitesse à laquelle celles-ci doivent être échangées. \cite[p. 3]{data_intensive}
\section{Composants}
Nous pouvons distinguer plusieurs types de composants:
L'infrastructure est destinée à supporter deux types d'applications:
\begin{enumerate}
\item \textbf{Les composants fonctionnels}, ceux sans qui l'application fonctionnerait de manière partielle, inadéquate, ou avec des temps de réponse inadapté
\item \textbf{Les composants périphériques}, c'est-à-dire les composants qui aident à avoir une architecture système résiliente, évolutive et maintenable
\item \textbf{Les composants de supervision}, qui permettent de s'assurer que tout fonctionne correctement, et qu'aucun incident n'est prévu ou n'a été constaté récemment.
\item
Les applications consommant principalement des cycles processeur (\textit{Compute-intensive applications}).
\item
Les applications consommant intensivement des données (\textit{Data-intensive applications}).
Une application consommant principalement des données est rarement limitée par la puisse du CPU, mais plus souvent par la quantité et la complexité des structures de données, et la vitesse à laquelle celles-ci doivent être échangées. \cite[p. 3]{data_intensive}
\end{enumerate}
\subsection{Composants fonctionnels}
Au niveau des composants destinés à épauler ces applications, nous pouvons distinguer les types suivants:
\begin{enumerate}
\item
\textbf{Les composants fonctionnels}, ceux sans qui l'application fonctionnerait de manière partielle, inadéquate, ou avec des temps de réponse inadapté
\item
\textbf{Les composants périphériques}, c'est-à-dire les composants qui aident à avoir une architecture système résiliente, évolutive et maintenable
\item
\textbf{Les composants de supervision}, qui permettent de s'assurer que tout fonctionne correctement, et qu'aucun incident n'est prévu ou n'a été constaté récemment.
\end{enumerate}
\section{Composants fonctionnels}
\begin{figure}[H]
\centering
@ -37,13 +45,13 @@ Une application \textit{data-intensive} est généralement composée des blocs f
\hline
\end{tabular}
\subsubsection{Bases de données}
\subsection{Bases de données}
\subsubsection{Tâches asynchrones}
\subsection{Tâches asynchrones}
\subsubsection{Mise en cache}
\subsection{Mise en cache}
\subsection{Composants périphériques}
\section{Composants périphériques}
Les composants périphériques gravitent autour du fonctionnement normal de l'application.
Ce sont les "petites mains" qui aident à ce que l'application soit résiliente ou que la charge soit amoindrie ou répartie entre plusieurs instances.
@ -99,40 +107,46 @@ Si nous schématisons l'infrastructure et le chemin parcouru par une requête, n
\includegraphics{images/diagrams/architecture.png}
\subsubsection{Firewall}
\subsection{Firewall}
\subsubsection{Reverse proxy}
\subsection{Reverse proxy}
Le principe du \textbf{proxy inverse} est de pouvoir rediriger du trafic entrant vers une application hébergée sur le système. Il serait tout à fait possible de rendre notre application directement accessible depuis l'extérieur, mais le proxy a aussi l'intérêt de pouvoir élever la sécurité du serveur (SSL) et décharger le serveur applicatif grâce à un mécanisme de cache ou en compressant certains résultats \footnote{\url{https://fr.wikipedia.org/wiki/Proxy_inverse}}
\subsubsection{Répartiteur de charge (\textit{Load balancer})}
\subsection{Répartiteur de charge (\textit{Load balancer})}
Les répartiteurs de charges sont super utiles pour donner du mou à l'infrastructure:
\begin{enumerate}
\item Maintenance et application de patches,
\item Répartition des utilisateurs connectés,
\item \ldots
\item
Maintenance et application de patches,
\item
Répartition des utilisateurs connectés,
\item
\ldots
\end{enumerate}
\subsubsection{Serveurs d'application (\textit{Workers})}
\subsection{Serveurs d'application (\textit{Workers})}
Processus et threads.
Au niveau logiciel (la partie mise en subrillance ci-dessus), la requête arrive dans les mains du processus Python, qui doit encore
\begin{enumerate}
\item effectuer le routage des données,
\item trouver la bonne fonction à exécuter,
\item récupérer les données depuis la base de données,
\item effectuer le rendu ou la conversion des données,
\item et renvoyer une réponse à l'utilisateur.
\item
Effectuer le routage des données,
\item
Trouver la bonne fonction à exécuter,
\item
Récupérer les données depuis la base de données,
\item
Effectuer le rendu ou la conversion des données,
\item
Renvoyer une réponse à l'utilisateur.
\end{enumerate}
\subsection{Composants de supervision}
\section{Composants de supervision}
\begin{tabular}{|p{0.2\linewidth}|p{0.55\linewidth}|p{0.15\linewidth}|}
\hline
@ -146,12 +160,12 @@ Au niveau logiciel (la partie mise en subrillance ci-dessus), la requête arrive
\hline
\end{tabular}
\subsubsection{Supervision des processus}
\subsection{Supervision des processus}
https://circus.readthedocs.io/en/latest/, https://uwsgi-docs.readthedocs.io/en/latest/, statsd
\subsubsection{Journaux}
\subsection{Journaux}
La présence de journaux, leur structure et de la définition précise de leurs niveaux est essentielle; ce sont eux qui permettent d'obtenir des informations quant au statut de l'application:
@ -171,20 +185,20 @@ Low printer toner is not an ERROR.
Chaque évènement est associé à un niveau; celui-ci indique sa criticité et sa émet un premier tri quant à sa pertinence.
\begin{itemize}
\item
\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, \ldots
\item
\textbf{WARN}: Regroupe les informations qui pourraient potentiellement devenir des erreurs.
\item
\textbf{ERROR}: Indique les informations internes - Erreur lors de l'appel d'une API, erreur interne, \ldots
\item
\textbf{FATAL} (ou \textbf{EXCEPTION}): \ldots généralement suivie d'une terminaison du programme - Bind raté d'un socket, etc.
\item
\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, \ldots
\item
\textbf{WARN}: Regroupe les informations qui pourraient potentiellement devenir des erreurs.
\item
\textbf{ERROR}: Indique les informations internes - Erreur lors de l'appel d'une API, erreur interne, \ldots
\item
\textbf{FATAL} (ou \textbf{EXCEPTION}): \ldots généralement suivie d'une terminaison du programme - Bind raté d'un socket, etc.
\end{itemize}
\subsubsection{Flux d'évènements}
\subsection{Flux d'évènements}
La configuration des \emph{loggers} est relativement simple, un peu plus complexe si nous nous penchons dessus, et franchement complète si nous creusons encore.
Il est ainsi possible de définir des formattages, différents gestionnaires (\emph{handlers}) et loggers distincts, en fonction de nos applications.
@ -217,7 +231,7 @@ Pour utiliser nos loggers, il suffit de copier le petit bout de code suivant:
\href{https://docs.djangoproject.com/en/stable/topics/logging/\#examples}{Par
exemples}.
\subsubsection{Exploitation des journaux, télémétrie}
\subsection{Exploitation des journaux, télémétrie}
Des erreurs sur un environnement de production arriveront, tôt ou tard, et seront sans doute plus compliquée à corriger qu'un morceau de code dans un coin du code.
L'exploitation des journaux permettra de comprendre, analyser, voire corriger, certains incidents.
@ -238,9 +252,9 @@ La solution consiste à agréger vos journaux à un seul et même endroit:
CC https://mattsegal.dev/django-monitoring-stack.html
\subsubsection{Sumologic}
\subsection{Sumologic}
\subsubsection{Alternatives}
\subsection{Alternatives}
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}.
@ -276,6 +290,6 @@ Histoire de schématiser, toute équipe se retrouve à un moment où un autre da
Et pour cause: une fois que nous aurons trouvé une joyeuse victime qui osera braver le danger, il y aura systématiquement des imprévus, des petits détails qui auront été oubliés sur le côté de la route, et qui feront lâchement planter les environnements.
Et puisque nous n'aurons pas (encore) de télémétrie, le seul moment où nous comprendrons qu'il y a un problème, sera quand un utilisateur viendra se plaindre.
\subsubsection{Statsd}
\subsection{Statsd}
https://www.datadoghq.com/blog/statsd/

View File

@ -700,6 +700,9 @@ que son propre identifiant:
COMMIT;
\end{minted}
Une bonne pratique consiste à ajouter un "autre" identifiant pour un modèle susceptible d'être interrogé.
Nous pensons ici à un UUID ou à un slug \index{slug}, qui permettrait d'avoir une sorte de clé sémantique associée à un object; ceci évite également d'avoir des identifiants qui soient trop facilement récupérables.
\subsection{Héritage classique}
L'héritage classique est généralement déconseillé, car il peut

View File

@ -158,6 +158,7 @@ C'est en ça que consistent les \href{https://www.djangopackages.com/}{paquets D
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.
Une bonne pratique consiste à \textbf{limiter à cinq} le nombre de modèles différents dans chaque application.
\subsection{manage.py}
@ -691,6 +692,12 @@ En continuant de cette manière (ie. Ecriture du code et des tests, vérificatio
A noter que tester le modèle en lui-même (ses attributs ou champs) ou des composants internes à Django n'a pas de sens: cela reviendrait à mettre en doute son fonctionnement interne.
Selon le principe du SRP \ref{SRP}, c'est le framework lui-même qui doit en assurer la maintenance et le bon fonctionnement.
\section{Licence}
Choisissez une licence!
Si votre projet n'a aucune licence, vous pourriez être tenu responsable.
En cas de désastre médical ou financier, cela peut faire toute la différence.
\section{Conclusions}
Comme nous l'avons vu dans la première partie, Django est un framework complet, intégrant tous les mécanismes nécessaires à la bonne évolution d'une application.

View File

@ -84,7 +84,14 @@ De cette manière, dans nos templates, on peut à présent construire un lien ve
<a href="{% url 'wishlists' %}">{{ yearvar }} Archive</a>
\end{minted}
De la même manière, on peut également récupérer l'URL de destination pour n'importe quel libellé, de la manière suivante:
De la même manière, on peut également récupérer l'URL de destination pour n'importe quel libellé, d'une des deux manières suivantes:
\begin{minted}{python}
from django.urls import reverse
wishlists_url = reverse('wishlists')
\end{minted}
\begin{minted}{python}
from django.core.urlresolvers import reverse_lazy

View File

@ -9,3 +9,22 @@ Les fonctions
\section{Classes}\label{CBV}
Les \textit{Class Based Views} ne sont jamais que des classes qui encapsulent certains comportements, comme nous l'avons vu en (cf. \#).
La classe présentant le comportement le plus proche d'une fonction est la classe \texttt{View} que l'on trouve dans le paquet \texttt{django.views.generic}:
\begin{minted}{python}
from django.views.generic import View
class WishListView(View):
def get(self):
pass
def post(self):
pass
\end{minted}
Le premier avantage des \textit{CBVs} est de pouvoir isoler les conditions liées au type de méthode HTTP \texttt{if request.method == "GET": ... elif request.method == "POST": ...}
La principale \textit{cheat-sheet} est \href{https://ccbv.co.uk/}{Django Class-Based View inspector}.

1
images/arch-structure Normal file
View File

@ -0,0 +1 @@
<mxfile host="Electron" modified="2022-05-23T10:59:53.794Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/16.5.1 Chrome/96.0.4664.110 Electron/16.0.7 Safari/537.36" etag="Ck-ryfskyNGh9GZ3a6UR" version="16.5.1" type="device"><diagram id="uHdZmcEhaC1admDXuta1" name="Page-1">zZdNb6MwEIZ/DdpTJcCEkGOafkpbrXYjdXurLDwNVg1GZlzI/vo1wYQgt1V7aOGC7HfGH/PYjG2PbPLmWtEyu5MMhBf6rPHIhReGCVmYbyvsrRAnnbBTnHVSMAhb/g+s6FtVcwbVyBGlFMjLsZjKooAURxpVStZjtycpxqOWdAeOsE2pcNW/nGFmowiXg34DfJf1IwfxqrPktHe2kVQZZbI+kcilRzZKSuxKebMB0bLruXTtrt6wHiemoMCPNCjWv5T27x+SR33z+4zK2+XP9Vlk43ihQtuI7Wxx3yNQUhcM2l58j5zXGUfYljRtrbVZc6NlmAtTC0zRdgcKoXlzosExfLNtQOaAam9cbIPYArM7Zmmr9YA/iKyWnaAnvSO1S7479jxQMQUL5jOQEgfSuiwFTylyWVTvAAu+BdhyDCx5BVj4GrAv47VyeF2Y39PbEG+9gtnxOsKZDNjCd4D90QXyHGbHKp6cVeCwuuOMCahNTHPDFfqT4wodXNt9hYd/MWn3l89+QFMKyfGQzWZHMJqcIHEI3nOFmgpezRPZ5AfAInI3HagX0Gp2yZ9Mn/wXLiyU6XN7MZ0brOmzf+yelN29ogKq58Yr+sL0b6rD2+FgO3mAkcv/</diagram></mxfile>

View File

@ -91,6 +91,12 @@
\chapter{Conclusions}
\appendix
\part{Annexes}
\chapter{Grafana}
\backmatter
\part{Ressources}

View File

@ -1,3 +1,12 @@
@book{boring_stuff,
title = {Automate the Boring Stuff with Python},
booktitle = {Practical Programming For Total Beginners},
author = {Al Sweigart},
year = {2020},
editor = {No Starch Press},
publisher = {William Pollock},
edition = {2nd edition}
}
@book{clean_architecture,
title = {Clean Architecture, A Craftman's Guide to Software Structure and Design},
author = {Robert C. Martin},
@ -6,12 +15,6 @@
year = {2018},
type = {Book}
}
@book{other_side,
author = {Aurélie Jean},
title = {De l'autre côté de la machine},
year = {2020},
publisher = {Editions de l'Observatoire},
}
@book{clean_code,
title = {Clean Code, a Handbook of Agile Software Craftmanship},
author = {Robert C. Martin},
@ -20,6 +23,13 @@
year = {2009},
type = {Book}
}
@book{devops_handbook,
title = {The DevOps Handbook, How to create World-class Agility, Reliability and Security in Technology Organizations},
author = {Gene Kim and Jez Humble and Patrick Debois and John Willis},
publisher = {IT Revolution},
year = {2016},
type = {Book}
}
@book{expert_python,
title = {Expert Python Programming},
author = {Jaworski, Michal and Ziadé, Tarek},
@ -28,21 +38,11 @@
edition = {4th edition},
type = {Book}
}
@book{devops_handbook,
title = {The DevOps Handbook, How to create World-class Agility, Reliability and Security in Technology Organizations},
author = {Gene Kim and Jez Humble and Patrick Debois and John Willis},
publisher = {IT Revolution},
year = {2016},
type = {Book}
}
@book{boring_stuff,
title = {Automate the Boring Stuff with Python},
booktitle = {Practical Programming For Total Beginners},
author = {Al Sweigart},
@book{other_side,
author = {Aurélie Jean},
title = {De l'autre côté de la machine},
year = {2020},
editor = {No Starch Press},
publisher = {William Pollock},
edition = {2nd edition}
publisher = {Editions de l'Observatoire},
}
@book{maintainable_software,
title = {Building Maintainable Software},