Writing, again and again

This commit is contained in:
Fred Pauchet 2022-05-11 15:43:09 +02:00
parent 2f4718c002
commit c15e05349d
11 changed files with 234 additions and 257 deletions

View File

@ -450,3 +450,40 @@ Et dans le fichier crontab :
\section{Ansible}
\section{Docker-Compose}
(c/c Ced' - 2020-01-24)
Ça y est, j'ai fait un test sur mon portable avec docker et cookiecutter
pour django.
D'abords, après avoir installer docker-compose et les dépendances sous
debian, tu dois t'ajouter dans le groupe docker, sinon il faut être root
pour utiliser docker. Ensuite, j'ai relancé mon pc car juste relancé un
shell n'a pas suffit pour que je puisse utiliser docker avec mon compte.
Bon après c'est facile, un petit virtualenv pour cookiecutter, suivit
d'une installation du template django. Et puis j'ai suivi sans t
\url{https://cookiecutter-django.readthedocs.io/en/latest/developing-locally-docker.html}
Alors, il télécharge les images, fait un petit update, installe les
dépendances de dev, install les requirement pip \ldots\hspace{0pt}
Du coup, ça prend vite de la place: image.png
L'image de base python passe de 179 à 740 MB. Et là j'en ai pour presque
1,5 GB d'un coup.
Mais par contre, j'ai un python 3.7 direct et postgres 10 sans rien
faire ou presque.
La partie ci-dessous a été reprise telle quelle de
\href{https://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html}{la
documentation de cookie-cutter-django}.
le serveur de déploiement ne doit avoir qu'un accès en lecture au dépôt
source.
On peut aussi passer par fabric, ansible, chef ou puppet.

View File

@ -1,36 +0,0 @@
\chapter{Docker-Compose}
(c/c Ced' - 2020-01-24)
Ça y est, j'ai fait un test sur mon portable avec docker et cookiecutter
pour django.
D'abords, après avoir installer docker-compose et les dépendances sous
debian, tu dois t'ajouter dans le groupe docker, sinon il faut être root
pour utiliser docker. Ensuite, j'ai relancé mon pc car juste relancé un
shell n'a pas suffit pour que je puisse utiliser docker avec mon compte.
Bon après c'est facile, un petit virtualenv pour cookiecutter, suivit
d'une installation du template django. Et puis j'ai suivi sans t
\url{https://cookiecutter-django.readthedocs.io/en/latest/developing-locally-docker.html}
Alors, il télécharge les images, fait un petit update, installe les
dépendances de dev, install les requirement pip \ldots\hspace{0pt}
Du coup, ça prend vite de la place: image.png
L'image de base python passe de 179 à 740 MB. Et là j'en ai pour presque
1,5 GB d'un coup.
Mais par contre, j'ai un python 3.7 direct et postgres 10 sans rien
faire ou presque.
La partie ci-dessous a été reprise telle quelle de
\href{https://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html}{la
documentation de cookie-cutter-django}.
le serveur de déploiement ne doit avoir qu'un accès en lecture au dépôt
source.
On peut aussi passer par fabric, ansible, chef ou puppet.

View File

@ -1,2 +0,0 @@
\chapter{Graphs}

View File

@ -3,6 +3,8 @@
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:
\begin{enumerate}
@ -11,7 +13,7 @@ Nous pouvons distinguer plusieurs types de composants:
\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}
\subsection{Composants fonctionnels}
\begin{figure}[H]
\centering
@ -35,18 +37,26 @@ Une application \textit{data-intensive} est généralement composée des blocs f
\hline
\end{tabular}
\subsection{Bases de données}
\subsubsection{Bases de données}
\subsection{Tâches asynchrones}
\subsubsection{Tâches asynchrones}
\subsection{Mise en cache}
\subsubsection{Mise en cache}
\section{Composants périphériques}
\subsection{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.
Il s'agit des composants comme le proxy inverse ou les distributeurs de charge: ce sont des composants qui sont fortement recommandés, mais pas obligatoires à au bon fonctionnement de l'application.
\begin{quote}
Hard disks are reported having a mean time to failure (MTTF) of about 1° to 50 years.
Thus, on a storage cluster with 10,000 disks, we should expect on average one disk to die per day. \cite[p. 7]{data_design}
\end{quote}
Avoir des composants périphériques correctement configurés permet d'anticiper ce type d'erreurs, et donc d'augmenter la résilience de l'application. \index{Résilience}
Certaines plateformes, comme Amazon Web Services \index{AWS}, favorisent la flexibilité et l'eslasticité plutôt que la disponibilité d'une seule machine. \cite[p. 8]{data_design}
C'est donc une bonne idée de faire en sorte que des erreurs d'indisponibilité peuvent arriver \footnote{Netflix a par exemple développer le \href{https://github.com/netflix/chaosmonkey}{Chaos Monkey}, qui s'occupe d'éteindre au hasard des machines virtuels et containers dans un environnement de production, juste pour faire en sorte que les équipes soient drillées à développer toutes sortes de mécanismes de remise en service - }.
\begin{tabular}{|p{0.2\linewidth}|p{0.55\linewidth}|p{0.15\linewidth}|}
\hline
@ -62,6 +72,8 @@ Il s'agit des composants comme le proxy inverse ou les distributeurs de charge:
\hline
Healthcheck & & Supervisord \\
\hline
Télémétrie & & \\
\hline
\end{tabular}
Si nous schématisons l'infrastructure et le chemin parcouru par une requête, nous pourrions arriver à la synthèse suivante:
@ -92,18 +104,26 @@ Si nous schématisons l'infrastructure et le chemin parcouru par une requête, n
\includegraphics{images/diagrams/architecture.png}
\subsection{Firewall}
\subsubsection{Firewall}
\subsection{Reverse proxy}
\subsubsection{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}}
\subsection{Répartiteur de charge (\textit{Load balancer})}
\subsubsection{Répartiteur de charge (\textit{Load balancer})}
\subsection{Serveurs d'application (\textit{Workers})}
\subsubsection{Serveurs d'application (\textit{Workers})}
\section{Composants de supervision}
\subsubsection{Télémétrie}
\begin{quote}
Once a rocket has left the ground, telemetry is essential for tracking what's happening and for understanding failures \cite[p. 10]{data_design}
\end{quote}
Le
\subsection{Composants de supervision}
\begin{tabular}{|p{0.2\linewidth}|p{0.55\linewidth}|p{0.15\linewidth}|}
\hline
@ -117,9 +137,9 @@ Le principe du \textbf{proxy inverse} est de pouvoir rediriger du trafic entrant
\hline
\end{tabular}
\subsection{Supervision des processus}
\subsubsection{Supervision des processus}
\subsection{Journaux}
\subsubsection{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:
@ -185,7 +205,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}.
\subsection{Exploitation des journaux}
\subsubsection{Exploitation des journaux}
\begin{enumerate}
\item

View File

@ -1,15 +1,25 @@
\chapter{Fiabilité, évolutivité et maintenabilité}
\begin{quote}
The primary cost of maintenance is in spelunking and risk
\cite[139]{clean_architecture}
The primary cost of maintenance is in spelunking and risk \cite[139]{clean_architecture}
--- Robert C. Martin
\end{quote}
Pour la méthode de travail et de développement, nous allons nous baser
sur les \href{https://12factor.net/fr/}{The Twelve-factor App} - ou plus
simplement les \textbf{12 facteurs}.
Que l'utilisateur soit humain, bot automatique ou client Web, la finalité d'un développement est de fournir des applications résilientes, pouvant être mises à l'échelle et maintenables \cite[p. 6]{data_design} :
\begin{itemize}
\item
La résilience consiste à ce que l'application continue à fonctionner \textit{correctement} - c'est-à-dire à ce qu'elle fournisse un service correct au niveau de performance désiré, même quand les choses passent mal.
Cela signifie que ces systèmes ont la capacité d'anticiper certains types d'erreurs, ou en tout cas, de les gérer de manière propre.
\item
La mise à échelle consiste à autoriser le système à \textit{grandir} - soit par le trafic pouvant être pris en charge, soit par son volume de données, soit par sa complexité.
\item
Au fil du temps, il est probable que plusieurs personnes se succèdent à travailler sur l'évolution d'une application, qu'ils travaillent sur sa conception ou sur son exploitation.
La maintenabilité consiste à faire en sorte que toute intervention puisse être réalisée de manière productive.
\end{itemize}
Pour la méthode de travail et de développement, nous allons nous baser sur les \href{https://12factor.net/fr/}{The Twelve-factor App} - ou plus simplement les \textbf{12 facteurs}.
Suivre ces concepts permet de:
\begin{enumerate}
@ -49,12 +59,8 @@ Comme dépôt, nous pourrons par exemple utiliser GitHub, Gitea ou Gitlab, suiva
\includegraphics{images/diagrams/12-factors-1.png}
Comme l'explique Eran Messeri, ingénieur dans le groupe Google Developer
Infrastructure: "Un des avantages d'utiliser un dépôt unique de sources,
est qu'il permet un accès facile et rapide à la forme la plus à jour du
code, sans aucun besoin de coordination. \cite[pp. 288-298]{devops_handbook}.
Ce cépôt n'est pas uniquement destiné à hébergé le code source, mais
également à d'autres artefacts et autres formes de connaissance:
Comme l'explique Eran Messeri, ingénieur dans le groupe Google Developer Infrastructure: "Un des avantages d'utiliser un dépôt unique de sources, est qu'il permet un accès facile et rapide à la forme la plus à jour du code, sans aucun besoin de coordination. \cite[pp. 288-298]{devops_handbook}.
Ce cépôt n'est pas uniquement destiné à hébergé le code source, mais également à d'autres artefacts et autres formes de connaissance:
\begin{itemize}
\item
@ -73,30 +79,18 @@ Ce cépôt n'est pas uniquement destiné à hébergé le code source, mais
\section{Déclaration explicite et isolation des dépendances}
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}.
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, ...)
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.
Lors de la création d'un nouvel environnement vierge, il suffira d'utiliser ce
fichier comme paramètre afin d'installer les prérequis au bon
fonctionnement de notre application.
Lors de la création d'un nouvel environnement vierge, il suffira d'utiliser ce fichier comme paramètre afin d'installer les prérequis au bon fonctionnement de notre application.
Ceci autorise une reproductibilité quasi parfaite de l'environnement.
Il est important de bien "épingler" les versions liées aux dépendances
de l'application. Cela peut éviter des effets de bord comme une nouvelle
version d'une librairie dans laquelle un bug aurait pu avoir été
introduit. Parce qu'il arrive que ce genre de problème apparaisse, et
lorsque ce sera le cas, ce sera systématiquement au mauvais moment \footnote{Le paquet PyLint dépend par exemple d'Astroid; \href{https://github.com/PyCQA/pylint-django/issues/343}{en janvier 2022}, ce dernier a été mis à jour sans respecter le principe de versions sémantiques et introduisant une régression. PyLint spécifiait que sa dépendance avec Astroid devait respecter une version ~2.9. Lors de sa mise à jour en 2.9.1, Astroid a introduit un changement majeur, qui faisait planter Pylint. L'épinglage explicite aurait pu éviter ceci.}
Il est important de bien "épingler" les versions liées aux dépendances de l'application. Cela peut éviter des effets de bord comme une nouvelle version d'une librairie dans laquelle un bug aurait pu avoir été introduit.
Parce qu'il arrive que ce genre de problème apparaisse, et lorsque ce sera le cas, ce sera systématiquement au mauvais moment \footnote{Le paquet PyLint dépend par exemple d'Astroid; \href{https://github.com/PyCQA/pylint-django/issues/343}{en janvier 2022}, ce dernier a été mis à jour sans respecter le principe de versions sémantiques et introduisant une régression. PyLint spécifiait que sa dépendance avec Astroid devait respecter une version ~2.9. Lors de sa mise à jour en 2.9.1, Astroid a introduit un changement majeur, qui faisait planter Pylint. L'épinglage explicite aurait pu éviter ceci.}
\section{Configuration applicative}
@ -128,32 +122,17 @@ 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 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 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 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.
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, ... directement \emph{via} des variables d'environnement.
\includegraphics{images/12factors/attached-resources.png}
Nous serons ravis de pouvoir simplement modifier une chaîne
\texttt{sqlite:////tmp/my-tmp-sqlite.db} en
\texttt{psql://user:pass@127.0.0.1:8458/db} lorsque ce sera nécessaire,
sans avoir à recompiler ou redéployer les modifications.
Nous serons ravis de pouvoir simplement modifier une chaîne \texttt{sqlite:////tmp/my-tmp-sqlite.db} en \texttt{psql://user:pass@127.0.0.1:8458/db} lorsque ce sera nécessaire, sans avoir à recompiler ou redéployer les modifications.
Ces ressources sont donc spécifiés grâce à des variables d'environnement, et chacune d'entre elles dispose également d'un \textbf{type}, afin de profiter d'une correspondance dynamique entre un moteur d'exécution et une information de configuration.
\section{Séparation des phases de construction}
@ -200,7 +179,7 @@ en HTTP ou via un autre protocole.
L'applicatoin fonctionne de manière autonome et expose un port (ici, le 8000).
Le serveur (= l'hôte) choisit d'appliquer une correspondance entre "son" port 443 et le port offert par l'application (8000).
\section{Connaissance et confiance des processys systèmes}
\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, ...
Si cela existe sur l'hôte hébergeant l'application, ne vous fatiguez pas: utilisez le.
@ -228,9 +207,7 @@ hôte, etc.).
\section{Similarité des environnements}
Conserver les différents environnements aussi similaires
que possible, et limiter les divergences entre un environnement de
développement et de production
Conserver les différents environnements aussi similaires que possible, et limiter les divergences entre un environnement de développement et de production.
L'exemple donné est un développeur qui utilise macOS, NGinx et SQLite, tandis que l'environnement de production tourne sur une CentOS avec Apache2 et PostgreSQL.
Faire en sorte que tous les environnements soient les plus similaires possibles limite les divergences entre environnements, facilite les déploiements et limite la casse et la découverte de modules non compatibles, au plus proche de la phase de développement, selon le principe de la corde d'Andon \cite[p. 140]{devops_handbook} \index{Andon} \footnote{Pour donner un exemple tout bête, SQLite utilise un
@ -240,6 +217,8 @@ Si vous faites vos développements sous SQLite et que vous rencontrez une URL de
Conserver des environements similaires limite ce genre de désagréments.}
Ceci permet également de proposer à nos utilisateurs un bac à sable dans lequel ils pourront explorer et réaliser des expérimentations en toute sécurité, sans quel cela n'ait d'impact sur un \textit{réel} environnement de production, où les conséquences pourraient être beaucoup plus graves. \cite[p. 9]{data_design}
\section{Journaux de flux évènementiels}
Une application ne doit jamais se soucier de l'endroit où les évènements qui la concerne seront écrits, mais se doit simplement de les envoyer sur la sortie \texttt{stdout}.
@ -255,33 +234,24 @@ Les applications 12facteurs favorisent les langages qui mettent un environnement
\section{Conclusions}
Une application devient nettement plus maintenable dès lors que l'équipe
de développement suit de près les différentes étapes de sa conception,
de la demande jusqu'à son aboutissement en production.
\cite[pp. 293-294]{devops_handbook}.
Une application devient nettement plus maintenable dès lors que l'équipe de développement suit de près les différentes étapes de sa conception, de la demande jusqu'à son aboutissement en production. \cite[pp. 293-294]{devops_handbook}.
Au fur et à mesure que le code est délibérément construit pour être maintenable, l'équipe gagne en rapidité, en qualité et en fiabilité de déploiement, ce qui facilite les tâches opérationnelles:
\begin{enumerate}
\item
Activation d'une télémétrie suffisante dans les applications et les
environnements
Activation d'une télémétrie suffisante dans les applications et les environnements
\item
Conservation précise des dépendances nécessaires
\item
Résilience des services et plantage élégant (i.e. \textbf{sans finir
sur un SEGFAULT avec l'OS dans les choux et un écran bleu})
Résilience des services et plantage élégant (i.e. \textbf{sans finir un SEGFAULT avec l'OS dans les choux et un écran bleu})
\item
Compatibilité entre les différentes versions (n+1, \ldots\hspace{0pt})
Compatibilité entre les différentes versions (n+1, \ldots)
\item
Gestion de l'espace de stockage associé à un environnement (pour
éviter d'avoir un environnement de production qui fait 157
Tera-octets)
Gestion de l'espace de stockage associé à un environnement (pour éviter d'avoir un environnement de production qui fait 157 Tera-octets)
\item
Activation de la recherche dans les logs
\item
Traces des requêtes provenant des utilisateurs, indépendamment des
services utilisés
Traces des requêtes provenant des utilisateurs, indépendamment des services utilisés
\item
Centralisation de la configuration (\textbf{via} ZooKeeper, par
exemple)
Centralisation de la configuration (\textbf{via} ZooKeeper, par exemple)
\end{enumerate}

View File

@ -1,8 +0,0 @@
\chapter{Poésie de la programmation}
\begin{quote}
The primary cost of maintenance is in spelunking and risk
\cite[139]{clean_architecture}
--- Robert C. Martin
\end{quote}

View File

@ -657,6 +657,11 @@ Si vous préférez rester avec le cadre de tests de Django, vous pouvez passer p
Ajoutez-le dans le fichier \texttt{requirements/base.txt}, et lancez une couverture de code grâce à la commande \texttt{coverage}.
La configuration peut se faire dans un fichier \texttt{.coveragerc} que vous placerez à la racine de votre projet, et qui sera lu lors de l'exécution.
\section{Gestion des exceptions}
Certains bogues causent des erreurs de mal-fonctionnement sont dus à une mauvaise conception endormie, qui ne se présente que dans certains cas très spécifiques, entourés d'une contexte inhabituel \cite[p. 9]{data_design}.
Il est primordial de gérer correctement ses exceptions, et de faire en sorte que celles qui peuvent être anticipées le soient dès la phase de développement.
\section{Gestion des versions de l'interpréteur}
\begin{verbatim}

View File

@ -1,4 +1,4 @@
\chapter{Arborescences}
\chapter{Arborescences et graphs}
On a un exemple de remplissage/vidage d'une closure table, mais il faudrait en fait présenter les listes adjacentes et les autres structures de données.
Comme ça on pourra introduire les graphs juste après.

View File

@ -9,7 +9,6 @@
\usepackage{setspace}
\usepackage{listing}
\usepackage{minted}
\usepackage{ulem}
\usepackage{graphics}
\usepackage{float}
\usepackage[export]{adjustbox}
@ -62,7 +61,6 @@
\include{chapters/heroku.tex}
\include{chapters/kubernetes.tex}
\include{chapters/deployment-tools.tex}
\include{chapters/deployment-processes.tex}
\chapter{Conclusions}
\include{parts/principles.tex}
@ -83,8 +81,8 @@
\include{chapters/api.tex}
\include{chapters/filters.tex}
\include{chapters/trees.tex}
\include{chapters/graphs.tex}
\include{chapters/i18n.tex}
\include{chapters/deployment-processes.tex}
\chapter{Conclusions}

View File

@ -55,7 +55,6 @@ Dans une version plus manuelle, cela pourrait se résumer à ces trois
étapes (la dernière étant formellement facultative):
\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\item
Démarrer un script,
\item
@ -66,10 +65,4 @@ Dans une version plus manuelle, cela pourrait se résumer à ces trois
technologie existe encore\ldots\hspace{0pt}).
\end{enumerate}
\begin{quote}
La poésie est "l'art d'évoquer et de suggérer les sensations, les impressions, les émotions les plus vives par l'union intense des sons, des rythmes, des harmonies, en particulier par les vers."
-- https://www.larousse.fr/dictionnaires/francais/po%C3%A9sie/61960
\end{quote}
Sans aller jusqu'à demander de développer vos algorithmes sur douze pieds, la programmation reste un art régit par un ensemble de bonnes pratiques, par des règles à respecter et par la nécessité de travailler avec d'autres personnes qui ont \sout{parfois} souvent une expérience, des compétences ou une approche différente.
Sans aller jusqu'à demander de développer vos algorithmes sur douze pieds, la programmation reste un art régit par un ensemble de bonnes pratiques, par des règles à respecter et par la nécessité de travailler avec d'autres personnes qui ont souvent une expérience, des compétences ou une approche différente.

View File

@ -1,9 +1,9 @@
\part{Services Oriented Applications}
Nous avons fait exprès de reprendre l'acronyme d'une \emph{Services Oriented Architecture} pour cette partie. L'objectif est de vous mettre
la puce à l'oreille quant à la finalité du développement: que l'utilisateur soit humain, bot automatique ou client Web, l'objectif est de fournir des applications résilientes, disponibles et accessibles.
Nous avons fait exprès de reprendre l'acronyme d'une \emph{Services Oriented Architecture} pour cette partie.
Dans cette partie, nous aborderons les vues, la mise en forme, la mise en page, la définition d'une interface REST, la définition d'une interface GraphQL et le routage d'URLs.
Dans cette partie, en page, la définition d'une interface REST, la définition d'une interface GraphQL et le routage d'URLs.
\begin{quote}