diff --git a/asciidoc-to-tex.tex b/asciidoc-to-tex.tex index 4087712..3ffbcae 100644 --- a/asciidoc-to-tex.tex +++ b/asciidoc-to-tex.tex @@ -88,528 +88,7 @@ \end{Highlighting} \end{Shaded} -\hypertarget{_dockerfile}{% -\subsubsection{Dockerfile}\label{_dockerfile}} -\begin{verbatim} -\end{verbatim} - -\hypertarget{_makefile}{% -\subsubsection{Makefile}\label{_makefile}} - - - - - -\hypertarget{_un_terminal}{% -\subsection{Un terminal}\label{_un_terminal}} - -\emph{A priori}, les IDE \footnote{Integrated Development Environment} -proposés ci-dessus fournissent par défaut ou \emph{via} des greffons un -terminal intégré. Ceci dit, disposer d'un terminal séparé facilite -parfois certaines tâches. - -A nouveau, si vous manquez d'idées: - -\begin{enumerate} -\def\labelenumi{\arabic{enumi}.} -\item - Si vous êtes sous Windows, téléchargez une copie de - \href{https://cmder.net/}{Cmder}. Il n'est pas le plus rapide, mais - propose une intégration des outils Unix communs (\texttt{ls}, - \texttt{pwd}, \texttt{grep}, \texttt{ssh}, \texttt{git}, - \ldots\hspace{0pt}) sans trop se fouler. -\item - Pour tout autre système, vous devriez disposer en natif de ce qu'il - faut. -\end{enumerate} - -\begin{figure} -\centering -\includegraphics{images/environment/terminal.png} -\caption{Mise en abîme} -\end{figure} - -\hypertarget{_un_gestionnaire_de_base_de_donnuxe9es}{% -\subsection{Un gestionnaire de base de -données}\label{_un_gestionnaire_de_base_de_donnuxe9es}} - -Django gère plusieurs moteurs de base de données. Certains sont gérés -nativement par Django (PostgreSQL, MariaDB, SQLite); \emph{a priori}, -ces trois-là sont disponibles pour tous les systèmes d'exploitation. -D'autres moteurs nécessitent des librairies tierces (Oracle, Microsoft -SQL Server). - -Il n'est pas obligatoire de disposer d'une application de gestion pour -ces moteurs: pour les cas d'utilisation simples, le shell Django pourra -largement suffire (nous y reviendrons). Mais pour faciliter la gestion -des bases de données elles-même, et si vous n'êtes pas à l'aise avec la -ligne de commande, choisissez l'une des applications d'administration -ci-dessous en fonction du moteur de base de données que vous souhaitez -utiliser. - -\begin{itemize} -\item - Pour \textbf{PostgreSQL}, il existe - \href{https://www.pgadmin.org/}{pgAdmin} -\item - Pour \textbf{MariaDB} ou \textbf{MySQL}, partez sur - \href{https://www.phpmyadmin.net/}{PHPMyAdmin} -\item - Pour \textbf{SQLite}, il existe - \href{https://sqlitebrowser.org/}{SQLiteBrowser} PHPMyAdmin ou - PgAdmin. -\end{itemize} - -\hypertarget{_un_gestionnaire_de_mots_de_passe}{% -\subsection{Un gestionnaire de mots de -passe}\label{_un_gestionnaire_de_mots_de_passe}} - -Nous en auront besoin pour gé(né)rer des phrases secrètes pour nos -applications. Si vous n'en utilisez pas déjà un, partez sur -\href{https://keepassxc.org/}{KeepassXC}: il est multi-plateformes, -suivi et s'intègre correctement aux différents environnements, tout en -restant accessible. - -\includegraphics{images/environment/keepass.png} - -\hypertarget{_un_systuxe8me_de_gestion_de_versions}{% -\subsection{Un système de gestion de -versions}\label{_un_systuxe8me_de_gestion_de_versions}} - -Il existe plusieurs systèmes de gestion de versions. Le plus connu à -l'heure actuelle est \href{https://git-scm.com/}{Git}, notamment pour sa -(très) grande flexibilité et sa rapidité d'exécution. Il est une aide -précieuse pour développer rapidement des preuves de concept, switcher -vers une nouvelle fonctionnalité, un bogue à réparer ou une nouvelle -release à proposer au téléchargement. Ses deux plus gros défauts -concerneraient peut-être sa courbe d'apprentissage pour les nouveaux -venus et la complexité des actions qu'il permet de réaliser. - -\begin{figure} -\centering -\includegraphics{images/xkcd-1597-git.png} -\caption{\url{https://xkcd.com/1597/}} -\end{figure} - -Même pour un développeur solitaire, un système de gestion de versions -(quel qu'il soit) reste indispensable. - -Chaque "\textbf{branche}" correspond à une tâche à réaliser: un bogue à -corriger (\emph{Hotfix A}), une nouvelle fonctionnalité à ajouter ou un -"\emph{truc à essayer}" \footnote{Oui, comme dans "Attends, j'essaie - vite un truc, si ça marche, c'est beau."} (\emph{Feature A} et -\emph{Feature B}). - -Chaque "\textbf{commit}" correspond à une sauvegarde atomique d'un état -ou d'un ensemble de modifications cohérentes entre elles.\footnote{Il - convient donc de s'abstenir de modifier le CSS d'une application et la - couche d'accès à la base de données, sous peine de se faire huer par - ses relecteurs au prochain stand-up.} De cette manière, il est -beaucoup plus facile pour le développeur de se concenter sur un sujet en -particulier, dans la mesure où celui-ci ne doit pas obligatoirement être -clôturé pour appliquer un changement de contexte. - -\begin{figure} -\centering -\includegraphics{images/diagrams/git-workflow.png} -\caption{Git en action} -\end{figure} - -Cas pratique: vous développez cette nouvelle fonctionnalité qui va -révolutionner le monde de demain et d'après-demain, quand, tout à coup -(!), vous vous rendez compte que vous avez perdu votre conformité aux -normes PCI parce les données des titulaires de cartes ne sont pas -isolées correctement. Il suffit alors de: - -\begin{enumerate} -\def\labelenumi{\arabic{enumi}.} -\item - sauver le travail en cours - (\texttt{git\ add\ .\ \&\&\ git\ commit\ -m\ {[}WIP{]}}) -\item - revenir sur la branche principale (\texttt{git\ checkout\ main}) -\item - créer un "hotfix" (\texttt{git\ checkout\ -b\ hotfix/pci-compliance}) -\item - solutionner le problème (sans doute un \texttt{;} en trop ?) -\item - sauver le correctif sur cette branche - (\texttt{git\ add\ .\ \&\&\ git\ commit\ -m\ "Did\ it!"}) -\item - récupérer ce correctif sur la branche principal - (\texttt{git\ checkout\ main\ \&\&\ git\ merge\ hotfix/pci-compliance}) -\item - et revenir tranquillou sur votre branche de développement pour - fignoler ce générateur de noms de dinosaures rigolos que l'univers - vous réclame à cor et à a cri - (\texttt{git\ checkout\ features/dinolol}) -\end{enumerate} - -Finalement, sachez qu'il existe plusieurs manières de gérer ces flux -d'informations. Les plus connus sont -\href{https://www.gitflow.com/}{Gitflow} et -\href{https://www.reddit.com/r/programming/comments/7mfxo6/a_branching_strategy_simpler_than_gitflow/}{Threeflow}. - -\hypertarget{_duxe9crire_ses_changements}{% -\subsubsection{Décrire ses -changements}\label{_duxe9crire_ses_changements}} - -La description d'un changement se fait \emph{via} la commande -\texttt{git\ commit}. Il est possible de lui passer directement le -message associé à ce changement grâce à l'attribut \texttt{-m}, mais -c'est une pratique relativement déconseillée: un \emph{commit} ne doit -effectivement pas obligatoirement être décrit sur une seule ligne. Une -description plus complète, accompagnée des éventuels tickets ou -références, sera plus complète, plus agréable à lire, et plus facile à -revoir pour vos éventuels relecteurs. - -De plus, la plupart des plateformes de dépôts présenteront ces -informations de manière ergonomique. Par exemple: - -\begin{figure} -\centering -\includegraphics{images/environment/gitea-commit-message.png} -\caption{Un exemple de commit affiché dans Gitea} -\end{figure} - -La première ligne est reprise comme titre (normalement, sur 50 -caractères maximum); le reste est repris comme de la description. - -\hypertarget{_un_systuxe8me_de_virtualisation}{% -\subsection{Un système de -virtualisation}\label{_un_systuxe8me_de_virtualisation}} - -Par "\emph{système de virtualisation}", nous entendons n'importe quel -application, système d'exploitation, système de containeurisation, -\ldots\hspace{0pt} 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} -\item - \href{https://www.virtualbox.org/}{VirtualBox} -\item - \href{https://www.vagrantup.com/}{Vagrant} -\item - \href{https://www.docker.com/}{Docker} -\item - \href{https://linuxcontainers.org/lxc/}{Linux Containers (LXC)} -\item - \href{https://docs.microsoft.com/fr-fr/virtualization/hyper-v-on-windows/quick-start/enable-hyper-v}{Hyper-V} -\end{itemize} - -Ces quelques propositions se situent un cran plus loin que la "simple" -isolation d'un environnement, puisqu'elles vous permettront de -construire un environnement complet. Elles constituent donc une étape -supplémentaires dans la configuration de votre espace de travail, mais -en amélioreront la qualité. - -Dans la suite, nous détaillerons Vagrant et Docker, qui constituent deux -solutions automatisables et multiplateformes, dont la configuration peut -faire partie intégrante de vos sources. - -\hypertarget{_vagrant}{% -\subsubsection{Vagrant}\label{_vagrant}} - -Vagrant consiste en un outil de création et de gestion d'environnements -virtualisés, en respectant toujours une même manière de travailler, -indépendamment des choix techniques et de l'infrastructure que vous -pourriez sélectionner. - -\begin{quote} -Vagrant is a tool for building and managing virtual machine environments -in a single workflow. With an easy-to-use workflow and focus on -automation, Vagrant lowers development environment setup time, increases -production parity, and makes the "works on my machine" excuse a relic of -the past. \footnote{\url{https://www.vagrantup.com/intro}} -\end{quote} - -La partie la plus importante de la configuration de Vagrant pour votre -projet consiste à placer un fichier \texttt{Vagrantfile} - \emph{a -priori} à la racine de votre projet - et qui contiendra les information -suivantes: - -\begin{itemize} -\item - Le choix du \emph{fournisseur} (\textbf{provider}) de virtualisation - (Virtualbox, Hyper-V et Docker sont natifs; il est également possible - de passer par VMWare, AWS, etc.) -\item - Une \emph{box}, qui consiste à lui indiquer le type et la version - attendue du système virtualisé (Debian 10, Ubuntu 20.04, etc. - et - \href{https://app.vagrantup.com/boxes/search}{il y a du choix}). -\item - La manière dont la fourniture (\textbf{provisioning}) de - l'environnement doit être réalisée: scripts Shell, fichiers, Ansible, - Puppet, Chef, \ldots\hspace{0pt} Choisissez votre favori :-) même s'il - est toujours possible de passer par une installation et une - maintenance manuelle, après s'être connecté sur la machine. -\item - Si un espace de stockage doit être partagé entre la machine virtuelle - et l'hôte -\item - Les ports qui doivent être transmis de la machine virtuelle vers - l'hôte. -\end{itemize} - -La syntaxe de ce fichier \texttt{Vagrantfile} est en -\href{https://www.ruby-lang.org/en/}{Ruby}. Vous trouverez ci-dessous un -exemple, généré (et nettoyé) après avoir exécuté la commande -\texttt{vagrant\ init}: - -\begin{Shaded} -\begin{Highlighting}[] -\CommentTok{\# {-}*{-} mode: ruby {-}*{-}} -\CommentTok{\# vi: set ft=ruby :} -\DataTypeTok{Vagrant}\NormalTok{.configure(}\StringTok{"2"}\NormalTok{) }\KeywordTok{do}\NormalTok{ |config|} - -\NormalTok{ config.vm.box = }\StringTok{"ubuntu/bionic64"} - -\NormalTok{ config.vm.network }\StringTok{"forwarded\_port"}\NormalTok{, }\StringTok{guest: }\DecValTok{80}\NormalTok{, }\StringTok{host: }\DecValTok{8080}\NormalTok{, }\StringTok{host\_ip: "127.0.0.1"} - -\NormalTok{ config.vm.provider }\StringTok{"virtualbox"} \KeywordTok{do}\NormalTok{ |vb|} -\NormalTok{ vb.gui = }\DecValTok{true} -\NormalTok{ vb.memory = }\StringTok{"1024"} - \KeywordTok{end} - -\NormalTok{ config.vm.provision }\StringTok{"shell"}\NormalTok{, }\StringTok{inline: }\NormalTok{\textless{}\textless{}{-}}\KeywordTok{SHELL} -\OtherTok{ apt{-}get update} -\OtherTok{ apt{-}get install {-}y nginx} -\OtherTok{ }\KeywordTok{SHELL} -\KeywordTok{end} -\end{Highlighting} -\end{Shaded} - -Dans le fichier ci-dessus, nous créons: - -\begin{itemize} -\item - Une nouvelle machine virtuelle (ie. \emph{invitée}) sous Ubuntu Bionic - Beaver, en x64 -\item - Avec une correspondance du port \texttt{80} de la machine vers le port - \texttt{8080} de l'hôte, en limitant l'accès à celui-ci - accédez à - \texttt{localhost:8080} et vous accéderez au port \texttt{80} de la - machine virtuelle. -\item - En utilisant Virtualbox comme backend - la mémoire vive allouée sera - limitée à 1Go de RAM et nous ne voulons pas voir l'interface graphique - au démarrage -\item - Et pour finir, nous voulons appliquer un script de mise à jour - \texttt{apt-get\ update} et installer le paquet \texttt{nginx} -\end{itemize} - -Par défaut, le répertoire courant (ie. le répertoire dans lequel notre -fichier \texttt{Vagrantfile} se trouve) sera synchronisé dans le -répertoire \texttt{/vagrant} sur la machine invitée. - -\hypertarget{_docker}{% -\subsubsection{Docker}\label{_docker}} - -(copié/collé de cookie-cutter-django) - -\begin{Shaded} -\begin{Highlighting}[] -\NormalTok{version: }\StringTok{\textquotesingle{}3\textquotesingle{}} - -\NormalTok{volumes:} -\NormalTok{ local\_postgres\_data: \{\}} -\NormalTok{ local\_postgres\_data\_backups: \{\}} - -\NormalTok{services:} -\NormalTok{ django: \&django} -\NormalTok{ build:} -\NormalTok{ context: .} -\NormalTok{ dockerfile: ./compose/local/django/Dockerfile} -\NormalTok{ image: khana\_local\_django} -\NormalTok{ container\_name: django} -\NormalTok{ depends\_on:} -\NormalTok{ {-} postgres} -\NormalTok{ volumes:} -\NormalTok{ {-} .:/app:z} -\NormalTok{ env\_file:} -\NormalTok{ {-} ./.envs/.local/.django} -\NormalTok{ {-} ./.envs/.local/.postgres} -\NormalTok{ ports:} -\NormalTok{ {-} }\StringTok{"8000:8000"} -\NormalTok{ command: /start} - -\NormalTok{ postgres:} -\NormalTok{ build:} -\NormalTok{ context: .} -\NormalTok{ dockerfile: ./compose/production/postgres/Dockerfile} -\NormalTok{ image: khana\_production\_postgres} -\NormalTok{ container\_name: postgres} -\NormalTok{ volumes:} -\NormalTok{ {-} local\_postgres\_data:/var/lib/postgresql/data:Z} -\NormalTok{ {-} local\_postgres\_data\_backups:/backups:z} -\NormalTok{ env\_file:} -\NormalTok{ {-} ./.envs/.local/.postgres} - -\NormalTok{ docs:} -\NormalTok{ image: khana\_local\_docs} -\NormalTok{ container\_name: docs} -\NormalTok{ build:} -\NormalTok{ context: .} -\NormalTok{ dockerfile: ./compose/local/docs/Dockerfile} -\NormalTok{ env\_file:} -\NormalTok{ {-} ./.envs/.local/.django} -\NormalTok{ volumes:} -\NormalTok{ {-} ./docs:/docs:z} -\NormalTok{ {-} ./config:/app/config:z} -\NormalTok{ {-} ./khana:/app/khana:z} -\NormalTok{ ports:} -\NormalTok{ {-} }\StringTok{"7000:7000"} -\NormalTok{ command: /start{-}docs} - -\NormalTok{ redis:} -\NormalTok{ image: redis:5.0} -\NormalTok{ container\_name: redis} - -\NormalTok{ celeryworker:} -\NormalTok{ \textless{}\textless{}: *django} -\NormalTok{ image: khana\_local\_celeryworker} -\NormalTok{ container\_name: celeryworker} -\NormalTok{ depends\_on:} -\NormalTok{ {-} redis} -\NormalTok{ {-} postgres} - -\NormalTok{ ports: []} -\NormalTok{ command: /start{-}celeryworker} - -\NormalTok{ celerybeat:} -\NormalTok{ \textless{}\textless{}: *django} -\NormalTok{ image: khana\_local\_celerybeat} -\NormalTok{ container\_name: celerybeat} -\NormalTok{ depends\_on:} -\NormalTok{ {-} redis} -\NormalTok{ {-} postgres} - -\NormalTok{ ports: []} -\NormalTok{ command: /start{-}celerybeat} - -\NormalTok{ flower:} -\NormalTok{ \textless{}\textless{}: *django} -\NormalTok{ image: khana\_local\_flower} -\NormalTok{ container\_name: flower} -\NormalTok{ ports:} -\NormalTok{ {-} }\StringTok{"5555:5555"} -\NormalTok{ command: /start{-}flower} -\end{Highlighting} -\end{Shaded} - -\begin{Shaded} -\begin{Highlighting}[] -\CommentTok{\# docker{-}compose.yml} -\NormalTok{version: }\StringTok{\textquotesingle{}3.8\textquotesingle{}} - -\NormalTok{services:} -\NormalTok{ web:} -\NormalTok{ build: .} -\NormalTok{ command: python /code/manage.py runserver 0.0.0.0:8000} -\NormalTok{ volumes:} -\NormalTok{ {-} .:/code} -\NormalTok{ ports:} -\NormalTok{ {-} 8000:8000} -\NormalTok{ depends\_on:} -\NormalTok{ {-} slqserver} -\NormalTok{ slqserver:} -\NormalTok{ image: mcr.microsoft.com/mssql/server:2019{-}latest} -\NormalTok{ environment:} -\NormalTok{ {-} }\StringTok{"ACCEPT\_EULA=Y"} -\NormalTok{ {-} }\StringTok{"SA\_PASSWORD=sqklgjqihagrtdgqk12§!"} -\NormalTok{ ports:} -\NormalTok{ {-} 1433:1433} -\NormalTok{ volumes:} -\NormalTok{ {-} ../sqlserver/data:/var/opt/mssql/data} -\NormalTok{ {-} ../sqlserver/log:/var/opt/mssql/log} -\NormalTok{ {-} ../sqlserver/secrets:/var/opt/mssql/secrets} -\end{Highlighting} -\end{Shaded} - -\begin{Shaded} -\begin{Highlighting}[] -\KeywordTok{FROM}\NormalTok{ python:3.8{-}slim{-}buster} - -\KeywordTok{ENV}\NormalTok{ PYTHONUNBUFFERED 1} -\KeywordTok{ENV}\NormalTok{ PYTHONDONTWRITEBYTECODE 1} - -\KeywordTok{RUN}\NormalTok{ apt{-}get update \textbackslash{}} - \CommentTok{\# dependencies for building Python packages} -\NormalTok{ \&\& apt{-}get install {-}y build{-}essential \textbackslash{}} - \CommentTok{\# psycopg2 dependencies} -\NormalTok{ \&\& apt{-}get install {-}y libpq{-}dev \textbackslash{}} - \CommentTok{\# Translations dependencies} -\NormalTok{ \&\& apt{-}get install {-}y gettext \textbackslash{}} - \CommentTok{\# cleaning up unused files} -\NormalTok{ \&\& apt{-}get purge {-}y {-}{-}auto{-}remove {-}o APT::AutoRemove::RecommendsImportant=false \textbackslash{}} -\NormalTok{ \&\& rm {-}rf /var/lib/apt/lists/*} - -\CommentTok{\# Requirements are installed here to ensure they will be cached.} -\KeywordTok{COPY}\NormalTok{ ./requirements /requirements} -\KeywordTok{RUN}\NormalTok{ pip install {-}r /requirements/local.txt} - -\KeywordTok{COPY}\NormalTok{ ./compose/production/django/entrypoint /entrypoint} -\KeywordTok{RUN}\NormalTok{ sed {-}i }\StringTok{\textquotesingle{}s/\textbackslash{}r$//g\textquotesingle{}}\NormalTok{ /entrypoint} -\KeywordTok{RUN}\NormalTok{ chmod +x /entrypoint} - -\KeywordTok{COPY}\NormalTok{ ./compose/local/django/start /start} -\KeywordTok{RUN}\NormalTok{ sed {-}i }\StringTok{\textquotesingle{}s/\textbackslash{}r$//g\textquotesingle{}}\NormalTok{ /start} -\KeywordTok{RUN}\NormalTok{ chmod +x /start} - -\KeywordTok{COPY}\NormalTok{ ./compose/local/django/celery/worker/start /start{-}celeryworker} -\KeywordTok{RUN}\NormalTok{ sed {-}i }\StringTok{\textquotesingle{}s/\textbackslash{}r$//g\textquotesingle{}}\NormalTok{ /start{-}celeryworker} -\KeywordTok{RUN}\NormalTok{ chmod +x /start{-}celeryworker} - -\KeywordTok{COPY}\NormalTok{ ./compose/local/django/celery/beat/start /start{-}celerybeat} -\KeywordTok{RUN}\NormalTok{ sed {-}i }\StringTok{\textquotesingle{}s/\textbackslash{}r$//g\textquotesingle{}}\NormalTok{ /start{-}celerybeat} -\KeywordTok{RUN}\NormalTok{ chmod +x /start{-}celerybeat} - -\KeywordTok{COPY}\NormalTok{ ./compose/local/django/celery/flower/start /start{-}flower} -\KeywordTok{RUN}\NormalTok{ sed {-}i }\StringTok{\textquotesingle{}s/\textbackslash{}r$//g\textquotesingle{}}\NormalTok{ /start{-}flower} -\KeywordTok{RUN}\NormalTok{ chmod +x /start{-}flower} - -\KeywordTok{WORKDIR}\NormalTok{ /app} - -\KeywordTok{ENTRYPOINT}\NormalTok{ [}\StringTok{"/entrypoint"}\NormalTok{]} -\end{Highlighting} -\end{Shaded} - -Voir comment nous pouvons intégrer toutes ces commandes au niveau de la -CI et au niveau du déploiement (Docker-compose ?) - -\hypertarget{_base_de_donnuxe9es}{% -\subsubsection{Base de données}\label{_base_de_donnuxe9es}} - -Parfois, SQLite peut être une bonne option: - -\begin{quote} -Write througput is the area where SQLite struggles the most, but there's -not a ton of compelling data online about how it fares, so I got some of -my own: I spun up a Equinix m3.large.x86 instance, and ran a slightly -modified1 version of the SQLite kvtest2 program on it. Writing 512 byte -blobs as separate transactions, in WAL mode with synchronous=normal3, -temp\_store=memory, and mmap enabled, I got 13.78μs per write, or -\textasciitilde72,568 writes per second. Going a bit larger, at 32kb -writes, I got 303.74μs per write, or \textasciitilde3,292 writes per -second. That's not astronomical, but it's certainly way more than most -websites being used by humans need. If you had 10 million daily active -users, each one could get more than 600 writes per day with that. -\end{quote} - -\begin{quote} -Looking at read throughput, SQLite can go pretty far: with the same test -above, I got a read throughput of \textasciitilde496,770 reads/sec -(2.013μs/read) for the 512 byte blob. Other people also report similar -results --- Expensify reports that you can get 4M QPS if you're willing -to make some slightly more involved changes and use a beefier server. -Four million QPS is enough that every internet user in the world could -make \textasciitilde70 queries per day, with a little headroom left -over4. Most websites don't need that kind of throughput. -cite:{[}consider\_sqlite{]} -\end{quote} \hypertarget{_duxe9marrer_un_nouveau_projet}{% \section{Démarrer un nouveau diff --git a/chapters/python.tex b/chapters/python.tex index 326ccf5..dff24da 100644 --- a/chapters/python.tex +++ b/chapters/python.tex @@ -770,91 +770,7 @@ L'exemple ci-dessous permettra, grâce à la commande \texttt{make\ coverage}, d Pour la petite histoire, \texttt{make} peu sembler un peu désuet, mais reste extrêmement efficace. -\section{Outils de développement} -\subsection{Environnement de développement} - -Concrètement, nous pourrions tout à fait nous limiter à Notepad ou Notepad++. -Mais à moins d'aimer se fouetter avec un câble USB, nous apprécions la complétion du code, la coloration syntaxique, l'intégration des tests unitaires et d'un debugger, ainsi que deux-trois sucreries qui feront plaisir à n'importe quel développeur. - -Si vous manquez d'idées ou si vous ne savez pas par où commencer: - -\begin{itemize} -\item - \href{https://vscodium.com/}{VSCodium}, avec les plugins - \href{https://marketplace.visualstudio.com/items?itemName=ms-python.python}{Python}et - \href{https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens}{GitLens} -\item - \href{https://www.jetbrains.com/pycharm/}{PyCharm} -\item - \href{https://www.vim.org/}{Vim} avec les plugins - \href{https://github.com/davidhalter/jedi-vim}{Jedi-Vim} et - \href{https://github.com/preservim/nerdtree}{nerdtree} -\end{itemize} - -Si vous hésitez, et même si Codium n'est pas le plus léger (la faute à -\href{https://www.electronjs.org/}{Electron}\ldots\hspace{0pt}), il fera -correctement son travail (à savoir: faciliter le vôtre), en intégrant -suffisament de fonctionnalités qui gâteront les papilles émoustillées du -développeur impatient. - -\begin{figure} - \centering - \includegraphics{images/environment/codium.png} - \caption{Codium en action} -\end{figure} - -\subsection{Terminal} - -\emph{A priori}, les IDE \footnote{Integrated Development Environment} -proposés ci-dessus fournissent par défaut ou \emph{via} des greffons un -terminal intégré. Ceci dit, disposer d'un terminal séparé facilite -parfois certaines tâches. - -A nouveau, si vous manquez d'idées: - -\begin{enumerate} -\item - Si vous êtes sous Windows, téléchargez une copie de - \href{https://cmder.net/}{Cmder}. Il n'est pas le plus rapide, mais - propose une intégration des outils Unix communs (\texttt{ls}, - \texttt{pwd}, \texttt{grep}, \texttt{ssh}, \texttt{git}, - \ldots\hspace{0pt}) sans trop se fouler. -\item - Pour tout autre système, vous devriez disposer en natif de ce qu'il - faut. -\end{enumerate} - -\begin{figure} - \centering - \includegraphics{images/environment/terminal.png} - \caption{Mise en abîme} -\end{figure} - -\subsection{Un gestionnaire de base de données} - -Django gère plusieurs moteurs de base de données. -Certains sont gérés nativement par Django (PostgreSQL, MariaDB, SQLite); \emph{a priori}, ces trois-là sont disponibles pour tous les systèmes d'exploitation. -D'autres moteurs nécessitent des librairies tierces (Oracle, Microsoft SQL Server). - -Il n'est pas obligatoire de disposer d'une application de gestion pour ces moteurs: pour les cas d'utilisation simples, le shell Django pourra largement suffire (nous y reviendrons). -Mais pour faciliter la gestion des bases de données elles-même, et si vous n'êtes pas à l'aise avec la -ligne de commande, choisissez l'une des applications d'administration -ci-dessous en fonction du moteur de base de données que vous souhaitez -utiliser. - -\begin{itemize} -\item - Pour \textbf{PostgreSQL}, il existe - \href{https://www.pgadmin.org/}{pgAdmin} -\item - Pour \textbf{MariaDB} ou \textbf{MySQL}, partez sur - \href{https://www.phpmyadmin.net/}{PHPMyAdmin} -\item - Pour \textbf{SQLite}, il existe - \href{https://sqlitebrowser.org/}{SQLiteBrowser} PHPMyAdmin ou - PgAdmin. -\end{itemize} \section{Conclusions (et intégration continue)} diff --git a/chapters/tools.tex b/chapters/tools.tex new file mode 100644 index 0000000..f61a675 --- /dev/null +++ b/chapters/tools.tex @@ -0,0 +1,493 @@ +\chapter{Outils de développement} + +\section{Environnement de développement} + +Concrètement, nous pourrions tout à fait nous limiter à Notepad ou Notepad++. +Mais à moins d'aimer se fouetter avec un câble USB, nous apprécions la complétion du code, la coloration syntaxique, l'intégration des tests unitaires et d'un debugger, ainsi que deux-trois sucreries qui feront plaisir à n'importe quel développeur. + +Si vous manquez d'idées ou si vous ne savez pas par où commencer: + +\begin{itemize} +\item + \href{https://vscodium.com/}{VSCodium}, avec les plugins + \href{https://marketplace.visualstudio.com/items?itemName=ms-python.python}{Python}et + \href{https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens}{GitLens} +\item + \href{https://www.jetbrains.com/pycharm/}{PyCharm} +\item + \href{https://www.vim.org/}{Vim} avec les plugins + \href{https://github.com/davidhalter/jedi-vim}{Jedi-Vim} et + \href{https://github.com/preservim/nerdtree}{nerdtree} +\end{itemize} + +Si vous hésitez, et même si Codium n'est pas le plus léger (la faute à +\href{https://www.electronjs.org/}{Electron}\ldots\hspace{0pt}), il fera +correctement son travail (à savoir: faciliter le vôtre), en intégrant +suffisament de fonctionnalités qui gâteront les papilles émoustillées du +développeur impatient. + +\begin{figure}[H] + \centering + \includegraphics{images/environment/codium.png} + \caption{Codium en action} +\end{figure} + +\section{Terminal} + +\emph{A priori}, les IDE \footnote{Integrated Development Environment} +proposés ci-dessus fournissent par défaut ou \emph{via} des greffons un +terminal intégré. Ceci dit, disposer d'un terminal séparé facilite +parfois certaines tâches. + +A nouveau, si vous manquez d'idées: + +\begin{enumerate} +\item + Si vous êtes sous Windows, téléchargez une copie de + \href{https://cmder.net/}{Cmder}. Il n'est pas le plus rapide, mais + propose une intégration des outils Unix communs (\texttt{ls}, + \texttt{pwd}, \texttt{grep}, \texttt{ssh}, \texttt{git}, + \ldots\hspace{0pt}) sans trop se fouler. +\item + Pour tout autre système, vous devriez disposer en natif de ce qu'il faut. +\end{enumerate} + +\begin{figure}[H] + \centering + \includegraphics{images/environment/terminal.png} + \caption{Mise en abîme} +\end{figure} + +\section{Un gestionnaire de base de données} + +Django gère plusieurs moteurs de base de données. +Certains sont gérés nativement par Django (PostgreSQL, MariaDB, SQLite); \emph{a priori}, ces trois-là sont disponibles pour tous les systèmes d'exploitation. +D'autres moteurs nécessitent des librairies tierces (Oracle, Microsoft SQL Server). + +Il n'est pas obligatoire de disposer d'une application de gestion pour ces moteurs: pour les cas d'utilisation simples, le shell Django pourra largement suffire (nous y reviendrons). +Mais pour faciliter la gestion des bases de données elles-même, et si vous n'êtes pas à l'aise avec la +ligne de commande, choisissez l'une des applications d'administration +ci-dessous en fonction du moteur de base de données que vous souhaitez +utiliser. + +\begin{itemize} +\item + Pour \textbf{PostgreSQL}, il existe + \href{https://www.pgadmin.org/}{pgAdmin} +\item + Pour \textbf{MariaDB} ou \textbf{MySQL}, partez sur + \href{https://www.phpmyadmin.net/}{PHPMyAdmin} +\item + Pour \textbf{SQLite}, il existe + \href{https://sqlitebrowser.org/}{SQLiteBrowser} PHPMyAdmin ou + PgAdmin. +\end{itemize} + +\section{Un gestionnaire de mots de passe} + +Nous en auront besoin pour gé(né)rer des phrases secrètes pour nos applications. +Si vous n'en utilisez pas déjà un, partez sur \href{https://keepassxc.org/}{KeepassXC}: il est multi-plateformes, suivi et s'intègre correctement aux différents environnements, tout en restant accessible. + +\includegraphics{images/environment/keepass.png} + +\subsection{Un système de gestion de versions} + +Il existe plusieurs systèmes de gestion de versions. +Le plus connu/utilisé à l'heure actuelle est \href{https://git-scm.com/}{Git}, notamment pour sa (très) grande flexibilité et sa rapidité d'exécution. +Il est une aide précieuse pour développer rapidement des preuves de concept, switcher vers une nouvelle fonctionnalité, un bogue à réparer ou une nouvelle release à proposer au téléchargement. +Ses deux plus gros défauts concernent sa courbe d'apprentissage pour les nouveaux venus et la complexité des actions qu'il permet de réaliser. + +\begin{figure}[H] +\centering +\includegraphics{images/xkcd-1597-git.png} +\caption{\url{https://xkcd.com/1597/}} +\end{figure} + +Même pour un développeur solitaire, un système de gestion de versions (quel qu'il soit) reste indispensable. + +Chaque "\textbf{branche}" correspond à une tâche à réaliser: un bogue à corriger (\emph{Hotfix A}), une nouvelle fonctionnalité à ajouter ou un "\emph{truc à essayer}" \footnote{Oui, comme dans "Attends, j'essaie vite un truc, si ça marche, c'est beau."} (\emph{Feature A} et \emph{Feature B}). + +Chaque "\textbf{commit}" correspond à une sauvegarde atomique d'un état ou d'un ensemble de modifications cohérentes entre elles.\footnote{Il convient donc de s'abstenir de modifier le CSS d'une application et la couche d'accès à la base de données, sous peine de se faire huer par ses relecteurs au prochain stand-up.} +De cette manière, il est beaucoup plus facile pour le développeur de se concenter sur un sujet en particulier, dans la mesure où celui-ci ne doit pas obligatoirement être clôturé pour appliquer un changement de contexte. + +\begin{figure}[H] +\centering +\includegraphics{images/diagrams/git-workflow.png} +\caption{Git en action} +\end{figure} + +Cas pratique: vous développez cette nouvelle fonctionnalité qui va révolutionner le monde de demain et d'après-demain, quand, tout à coup (!), vous vous rendez compte que vous avez perdu votre conformité aux +normes PCI parce les données des titulaires de cartes ne sont pas isolées correctement. +Il suffit alors de: + +\begin{enumerate} +\item + Sauver le travail en cours (\texttt{git\ add\ .\ \&\&\ git\ commit\ -m\ {[}WIP{]}}) +\item + Revenir sur la branche principale (\texttt{git\ checkout\ main}) +\item + Créer un "hotfix" (\texttt{git\ checkout\ -b\ hotfix/pci-compliance}) +\item + Solutionner le problème (sans doute un \texttt{;} en trop ?) +\item + Sauver le correctif sur cette branche + (\texttt{git\ add\ .\ \&\&\ git\ commit\ -m\ "Did\ it!"}) +\item + Récupérer ce correctif sur la branche principal + (\texttt{git\ checkout\ main\ \&\&\ git\ merge\ hotfix/pci-compliance}) +\item + Et revenir tranquillou sur votre branche de développement pour fignoler ce générateur de noms de dinosaures rigolos que l'univers vous réclame à cor et à a cri (\texttt{git\ checkout\ features/dinolol}) +\end{enumerate} + +Finalement, sachez qu'il existe plusieurs manières de gérer ces flux d'informations. +Les plus connus sont \href{https://www.gitflow.com/}{Gitflow} et \href{https://www.reddit.com/r/programming/comments/7mfxo6/a_branching_strategy_simpler_than_gitflow/}{Threeflow}. + + +\subsection{Décrire ses changements} + +La description d'un changement se fait \emph{via} la commande \texttt{git\ commit}. +Il est possible de lui passer directement le message associé à ce changement grâce à l'attribut \texttt{-m}, mais c'est une pratique relativement déconseillée: un \emph{commit} ne doit effectivement pas obligatoirement être décrit sur une seule ligne. +Une description plus complète, accompagnée des éventuels tickets ou références, sera plus complète, plus agréable à lire, et plus facile à revoir pour vos éventuels relecteurs. + +De plus, la plupart des plateformes de dépôts présenteront ces informations de manière ergonomique. Par exemple: + +\begin{figure}[H] +\centering +\includegraphics{images/environment/gitea-commit-message.png} +\caption{Un exemple de commit affiché dans Gitea} +\end{figure} + +La première ligne est reprise comme titre (normalement, sur 50 caractères maximum); le reste est repris comme de la description. + +\section{Bases de données} + +Parfois, SQLite peut être une bonne option: + +\begin{quote} +Write througput is the area where SQLite struggles the most, but there's not a ton of compelling data online about how it fares, so I got some of my own: I spun up a Equinix m3.large.x86 instance, and ran a slightly modified1 version of the SQLite kvtest2 program on it. +Writing 512 byte blobs as separate transactions, in WAL mode with synchronous=normal3, temp\_store=memory, and mmap enabled, I got 13.78$\mu$s per write, or \textasciitilde72,568 writes per second. Going a bit larger, at 32kb writes, I got 303.74$\mu$s per write, or \textasciitilde3,292 writes per second. +That's not astronomical, but it's certainly way more than most websites being used by humans need. +If you had 10 million daily active users, each one could get more than 600 writes per day with that. +\end{quote} + +\begin{quote} +Looking at read throughput, SQLite can go pretty far: with the same test above, I got a read throughput of \textasciitilde496,770 reads/sec (2.013$\mu$s/read) for the 512 byte blob. +Other people also report similar results + +--- Expensify reports that you can get 4M QPS if you're willing to make some slightly more involved changes and use a beefier server. +Four million QPS is enough that every internet user in the world could make \textasciitilde70 queries per day, with a little headroom left over. +Most websites don't need that kind of throughput. \cite{consider_sqlite} +\end{quote} + + +\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. +Les solutions sont nombreuses: + +\begin{itemize} +\item + \href{https://www.virtualbox.org/}{VirtualBox} +\item + \href{https://www.vagrantup.com/}{Vagrant} +\item + \href{https://www.docker.com/}{Docker} +\item + \href{https://linuxcontainers.org/lxc/}{Linux Containers (LXC)} +\item + \href{https://docs.microsoft.com/fr-fr/virtualization/hyper-v-on-windows/quick-start/enable-hyper-v}{Hyper-V} +\end{itemize} + +Ces quelques propositions se situent un cran plus loin que la "simple" isolation d'un environnement, puisqu'elles vous permettront de construire un environnement complet. +Elles constituent donc une étape supplémentaires dans la configuration de votre espace de travail, mais en amélioreront la qualité. + +Dans la suite, nous détaillerons Vagrant et Docker, qui constituent deux solutions automatisables et multiplateformes, dont la configuration peut faire partie intégrante de vos sources. + +\subsection{Vagrant} + +Vagrant consiste en un outil de création et de gestion d'environnements virtualisés, en respectant toujours une même manière de travailler, indépendamment des choix techniques et de l'infrastructure que vous pourriez sélectionner. + +\begin{quote} + Vagrant is a tool for building and managing virtual machine environments + in a single workflow. With an easy-to-use workflow and focus on + automation, Vagrant lowers development environment setup time, increases + production parity, and makes the "works on my machine" excuse a relic of + the past. \footnote{\url{https://www.vagrantup.com/intro}} + \end{quote} + + La partie la plus importante de la configuration de Vagrant pour votre + projet consiste à placer un fichier \texttt{Vagrantfile} - \emph{a + priori} à la racine de votre projet - et qui contiendra les information + suivantes: + + \begin{itemize} + \item + Le choix du \emph{fournisseur} (\textbf{provider}) de virtualisation + (Virtualbox, Hyper-V et Docker sont natifs; il est également possible + de passer par VMWare, AWS, etc.) + \item + Une \emph{box}, qui consiste à lui indiquer le type et la version + attendue du système virtualisé (Debian 10, Ubuntu 20.04, etc. - et + \href{https://app.vagrantup.com/boxes/search}{il y a du choix}). + \item + La manière dont la fourniture (\textbf{provisioning}) de + l'environnement doit être réalisée: scripts Shell, fichiers, Ansible, + Puppet, Chef, \ldots\hspace{0pt} Choisissez votre favori :-) même s'il + est toujours possible de passer par une installation et une + maintenance manuelle, après s'être connecté sur la machine. + \item + Si un espace de stockage doit être partagé entre la machine virtuelle + et l'hôte + \item + Les ports qui doivent être transmis de la machine virtuelle vers + l'hôte. + \end{itemize} + +La syntaxe de ce fichier \texttt{Vagrantfile} est en \href{https://www.ruby-lang.org/en/}{Ruby}. +Vous trouverez ci-dessous un exemple, généré (et nettoyé) après avoir exécuté la commande \texttt{vagrant\ init}: + +\begin{listing}[H] + \begin{minted}{ruby} + # -*- mode: ruby -*- + # vi: set ft=ruby : + + Vagrant.configure("2") do |config| + + config.vm.box = "ubuntu/bionic64" + config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: + "127.0.0.1" + + config.vm.provider "virtualbox" do |vb| + vb.gui = true + vb.memory = "1024" + end + + config.vm.provision "shell", inline: <<-SHELL + apt-get update + apt-get install -y nginx + SHELL + end + \end{minted} +\end{listing} + +Dans le fichier ci-dessus, nous créons: + +\begin{itemize} +\item + Une nouvelle machine virtuelle (ie. \emph{invitée}) sous Ubuntu Bionic Beaver, en x64 +\item + Avec une correspondance du port \texttt{80} de la machine vers le port \texttt{8080} de l'hôte, en limitant l'accès à celui-ci - accédez à \texttt{localhost:8080} et vous accéderez au port \texttt{80} de la machine virtuelle. +\item + En utilisant Virtualbox comme backend - la mémoire vive allouée sera limitée à 1Go de RAM et nous ne voulons pas voir l'interface graphique au démarrage +\item + Et pour finir, nous voulons appliquer un script de mise à jour \texttt{apt-get\ update} et installer le paquet \texttt{nginx} +\end{itemize} + +Par défaut, le répertoire courant (ie. le répertoire dans lequel notre fichier \texttt{Vagrantfile} se trouve) sera synchronisé dans le répertoire \texttt{/vagrant} sur la machine invitée. + +\subsection{Docker} + +(copié/collé de cookie-cutter) + +\begin{listing}[H] + \begin{verbatim} + version: '3' + + volumes: + local_postgres_data: {} + local_postgres_data_backups: {} + + services: + << description des services >> + \end{verbatim} +\end{listing} + +\begin{listing}[H] + \begin{verbatim} + django: &django + build: + context: . + dockerfile: ./compose/local/django/Dockerfile + image: khana_local_django + container_name: django + depends_on: + - postgres + volumes: + - .:/app:z + env_file: + - ./.envs/.local/.django + - ./.envs/.local/.postgres + ports: + - "8000:8000" + command: /start + \end{verbatim} +\end{listing} + +\begin{listing}[H] + \begin{verbatim} + postgres: + build: + context: . + dockerfile: ./compose/production/postgres/Dockerfile + image: khana_production_postgres + container_name: postgres + volumes: + - local_postgres_data:/var/lib/postgresql/data:Z + - local_postgres_data_backups:/backups:z + env_file: + - ./.envs/.local/.postgres + \end{verbatim} +\end{listing} + +\begin{listing}[H] + \begin{verbatim} + docs: + image: khana_local_docs + container_name: docs + build: + context: . + dockerfile: ./compose/local/docs/Dockerfile + env_file: + - ./.envs/.local/.django + volumes: + - ./docs:/docs:z + - ./config:/app/config:z + - ./khana:/app/khana:z + ports: + - "7000:7000" + command: /start-docs + \end{verbatim} +\end{listing} + +\begin{listing}[H] + \begin{verbatim} + redis: + image: redis:5.0 + container_name: redis + \end{verbatim} +\end{listing} + +\begin{listing}[H] + \begin{verbatim} + celeryworker: + <<: *django + image: khana_local_celeryworker + container_name: celeryworker + depends_on: + - redis + - postgres + ports: [] + command: /start-celeryworker + \end{verbatim} +\end{listing} + +\begin{listing}[H] + \begin{verbatim} + celerybeat: + <<: *django + image: khana_local_celerybeat + container_name: celerybeat + depends_on: + - redis + - postgres + ports: [] + command: /start-celerybeat + \end{verbatim} +\end{listing} + +\begin{listing}[H] + \begin{verbatim} + flower: + <<: *django + image: khana_local_flower + container_name: flower + ports: + - "5555:5555" + command: /start-flower + \end{verbatim} +\end{listing} + +\subsection{Docker-compose} + +\begin{listing}[H] + \begin{verbatim} + # docker-compose.yml + + version: '3.8' + services: + web: + build: . + command: python /code/manage.py runserver 0.0.0.0:8000 + volumes: + - .:/code + ports: + - 8000:8000 + depends_on: + - slqserver + + slqserver: + image: mcr.microsoft.com/mssql/server:2019-latest + environment: + - "ACCEPT_EULA=Y" + - "SA_PASSWORD=sqklgjqihagrtdgqk12§!" + ports: + - 1433:1433 + volumes: + - ../sqlserver/data:/var/opt/mssql/data + - ../sqlserver/log:/var/opt/mssql/log + - ../sqlserver/secrets:/var/opt/mssql/secrets + \end{verbatim} +\end{listing} + +\subsection{Dockerfile} + +\begin{listing}[H] +\begin{verbatim} + FROM python:3.8-slim-buster + + ENV PYTHONUNBUFFERED 1 + ENV PYTHONDONTWRITEBYTECODE 1 + + RUN apt-get update \ + + # dependencies for building Python packages + && apt-get install -y build-essential \ + # psycopg2 dependencies + && apt-get install -y libpq-dev \ + # Translations dependencies + && apt-get install -y gettext \ + # cleaning up unused files + && apt-get purge -y --auto-remove -o + APT::AutoRemove::RecommendsImportant=false \ + && rm -rf /var/lib/apt/lists/* + + # Requirements are installed here to ensure they will be cached. + COPY ./requirements /requirements + RUN pip install -r /requirements/local.txt + + COPY ./compose/production/django/entrypoint /entrypoint + RUN sed -i 's/\r$//g' /entrypoint + RUN chmod +x /entrypoint + + COPY ./compose/local/django/start /start + RUN sed -i 's/\r$//g' /start + RUN chmod +x /start + + COPY ./compose/local/django/celery/worker/start /start-celeryworker + RUN sed -i 's/\r$//g' /start-celeryworker + RUN chmod +x /start-celeryworker + + COPY ./compose/local/django/celery/beat/start /start-celerybeat + RUN sed -i 's/\r$//g' /start-celerybeat + RUN chmod +x /start-celerybeat + + COPY ./compose/local/django/celery/flower/start /start-flower + RUN sed -i 's/\r$//g' /start-flower + RUN chmod +x /start-flower + + WORKDIR /app + + ENTRYPOINT ["/entrypoint"] +\end{verbatim} +\end{listing} diff --git a/main.tex b/main.tex index d039db2..c55ffdc 100644 --- a/main.tex +++ b/main.tex @@ -50,6 +50,8 @@ \include{chapters/tests.tex} +\include{chapters/tools.tex} + \include{chapters/python.tex} \include{chapters/new-project.tex}