1375 lines
41 KiB
TeX
1375 lines
41 KiB
TeX
\documentclass{slides}
|
|
\addbibresource{slides.bib}
|
|
|
|
\title{Systèmes à objets répartis}
|
|
\subtitle{M1 Informatique, S8}
|
|
\date{Janvier 2026}
|
|
\titlegraphic{\flushright\includegraphics[height=1.3cm]{img/logos.png}\vspace{.5cm}}
|
|
|
|
\author{
|
|
\texorpdfstring{
|
|
\begin{table}[]
|
|
\begin{flushleft}
|
|
\begin{tabular}{ll}
|
|
& Vincent Lannurien~\inst{1} \\
|
|
& \url{vincent.lannurien@univ-brest.fr} \\
|
|
\end{tabular}
|
|
\end{flushleft}
|
|
\end{table}
|
|
}
|
|
{
|
|
Vincent Lannurien
|
|
}
|
|
}
|
|
|
|
\institute{
|
|
\texorpdfstring{
|
|
\begin{table}[]
|
|
\centering
|
|
\begin{flushleft}
|
|
\begin{tabular}{L}
|
|
\inst{1}~Lab-STICC, CNRS UMR 6285, Université de Bretagne Occidentale, Brest
|
|
\end{tabular}
|
|
\end{flushleft}
|
|
\end{table}
|
|
}
|
|
{
|
|
Lab-STICC, CNRS UMR 6285, Université de Bretagne Occidentale, Brest
|
|
}
|
|
}
|
|
|
|
\begin{document}
|
|
|
|
\maketitle
|
|
|
|
\begin{frame}{Introduction}
|
|
\begin{center}
|
|
\url{https://info-demo-sor.univ-brest.fr}
|
|
\end{center}
|
|
\end{frame}
|
|
|
|
\begin{framefont}{\small}
|
|
\begin{frame}[t]{Plan du cours}
|
|
\begin{columns}
|
|
\column{0.5\textwidth}
|
|
\tableofcontents%[hideallsubsections]
|
|
|
|
\column{0.5\textwidth}
|
|
\begin{center}
|
|
\includegraphics[width=0.9\columnwidth]{img/logos.png}
|
|
\end{center}
|
|
\end{columns}
|
|
\end{frame}
|
|
\end{framefont}
|
|
|
|
\section{Organisation de l'UE}
|
|
|
|
\begin{frame}{Organisation de l'UE -- Contenu}
|
|
\begin{itemize}
|
|
\item Objectifs :
|
|
\begin{itemize}
|
|
\item Développer une application suivant l'\textbf{architecture trois tiers}, s'appuyant sur des communications via \textbf{HTTP} et \textbf{WebSockets} ;
|
|
\item Comprendre les mécanismes pour l'\textbf{authentification} (avec ou sans état) d'un client auprès d'un serveur ;
|
|
\item S'initier au \textbf{déploiement} d'une application répartie à l'aide d'un \textit{reverse proxy}.
|
|
\end{itemize}
|
|
\item Prérequis :
|
|
\begin{itemize}
|
|
\item Côté client : HTML/CSS
|
|
\end{itemize}
|
|
\item Méthode :
|
|
\begin{itemize}
|
|
\item Un peu de cours...
|
|
\item Beaucoup de pratique !
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Organisation de l'UE -- Logistique}
|
|
\begin{itemize}
|
|
\item Volume horaire :
|
|
\begin{itemize}
|
|
\item CM : 3 séances de 2h (total : 6h)
|
|
\item TP : 8 séances de 2h (total : 16h)
|
|
\end{itemize}
|
|
\item Contrôle des connaissances :
|
|
\begin{itemize}
|
|
\item TP noté (2h sur cette partie du cours)
|
|
\item Examen final (2h en tout)
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\section{Introduction}
|
|
|
|
\begin{frame}{Contenu du cours}
|
|
\begin{itemize}
|
|
\item État et gestion de l'état
|
|
\begin{itemize}
|
|
\item Contrats
|
|
\begin{itemize}
|
|
\item Interfaces
|
|
\item \textit{Data Transfer Objects}
|
|
\end{itemize}
|
|
\item Persistance
|
|
\begin{itemize}
|
|
\item Base de données
|
|
\item Transactions
|
|
% \item Cache
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\item Protocoles
|
|
\begin{itemize}
|
|
\item HTTP
|
|
\begin{itemize}
|
|
\item \textit{Status codes}
|
|
\item \textit{CORS} (\textit{Cross-Origin Resource Sharing})
|
|
\end{itemize}
|
|
\item Authentification
|
|
\begin{itemize}
|
|
\item \textit{Tokens}
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\item Performances et profilage
|
|
\begin{itemize}
|
|
\item Instrumentation (serveur)
|
|
\item Inspecteur (client)
|
|
\item Injection de trafic
|
|
\end{itemize}
|
|
\item Déploiement
|
|
\begin{itemize}
|
|
\item SSL, certificats
|
|
\item \textit{Reverse proxy}
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Technologies utilisées}
|
|
\begin{itemize}
|
|
\item Côté serveur :
|
|
\begin{itemize}
|
|
\item Runtime (Deno)
|
|
\item Langage (TypeScript)
|
|
\item Framework (Oak)
|
|
\item Base de données (SQLite)
|
|
% \item Cache (Redis)
|
|
\end{itemize}
|
|
\item Côté client :
|
|
\begin{itemize}
|
|
\item Bundler (Vite)
|
|
\item Langage (TypeScript)
|
|
\item Framework (React)
|
|
\end{itemize}
|
|
\item Communications :
|
|
\begin{itemize}
|
|
\item Requêtes HTTP
|
|
\item WebSockets
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\section{Cas d'usage}
|
|
|
|
\begin{frame}{Présentation de l'application}
|
|
\begin{block}{Description}
|
|
L'application est une \textbf{plateforme de sondages en ligne}.
|
|
|
|
Elle permet à des utilisateurs de \textbf{créer des sondages} et d'ajouter des \textbf{options de réponse}.
|
|
|
|
Les participants peuvent \textbf{voter} pour une ou plusieurs options selon des règles définies par le créateur du sondage.
|
|
|
|
L'application gère également l'\textbf{authentification} des utilisateurs et assure la \textbf{persistance} des données.
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Présentation de l'application}
|
|
\begin{alertblock}{Acteurs}
|
|
Les acteurs de l'application sont les suivants :
|
|
|
|
\begin{itemize}
|
|
\item Utilisateur authentifié : peut créer des sondages, voter, et consulter les résultats ;
|
|
\item Utilisateur invité : peut voter (si autorisé) et consulter les résultats (si autorisé) ;
|
|
\item Administrateur : peut gérer les sondages et les utilisateurs.
|
|
\end{itemize}
|
|
\end{alertblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Présentation de l'application}
|
|
\begin{alertblock}{Fonctionnalités}
|
|
Les principales fonctionnalités de l'application peuvent être résumées ainsi :
|
|
|
|
\begin{itemize}
|
|
\item Création de sondages avec : titre, description, date de création, date d'expiration, statut (actif/inactif) ;
|
|
\item Ajout d'options à un sondage : texte descriptif ;
|
|
\item Vote pour une option de sondage ;
|
|
\item Consultation des résultats (nombre de votes par option) ;
|
|
\item Gestion des utilisateurs (inscription, authentification).
|
|
\end{itemize}
|
|
\end{alertblock}
|
|
\end{frame}
|
|
|
|
\section{Architecture : modèle client/serveur}
|
|
|
|
\begin{frame}{Vue d'ensemble}
|
|
|
|
\end{frame}
|
|
|
|
\begin{frame}{Monolithes ou microservices}
|
|
\centering
|
|
\includegraphics[width=.8\textwidth]{img/scaling-monolith.png}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Monolithes ou microservices}
|
|
\centering
|
|
\includegraphics[width=.8\textwidth]{img/scaling-uservices.png}
|
|
\end{frame}
|
|
|
|
\section{JavaScript, TypeScript et runtime}
|
|
|
|
\begin{frame}{JavaScript}
|
|
\centering
|
|
\includegraphics[width=.5\textwidth]{img/javascript-alert.png}
|
|
\end{frame}
|
|
|
|
\begin{frame}{JavaScript}
|
|
\begin{columns}
|
|
\column{.8\textwidth}
|
|
\begin{itemize}
|
|
\item 1995 : Brendan Eich développe en 10 jours un langage simple, interprété par le navigateur, pour dynamiser les pages web
|
|
\item 1997 : première standardisation par ECMA (\textit{European Computer Manufacturers Association}) sous le nom ECMAScript
|
|
\item 2005 : AJAX popularise les applications web dynamiques
|
|
\item 2008 : Google publie la machine virtuelle V8 pour l'exécution du code JavaScript dans Chrome
|
|
\item 2009 : Node.js étend l'utilisation de JavaScript au côté serveur
|
|
\item 2010 -- 2014 : émergence des frameworks et d'un outillage moderne pour JavaScript (jQuery, AngularJS, etc.)
|
|
\item 2015 : ECMAScript Edition 6 (ES6/ES2015) transforme le langage (modules, classes, \textit{arrow functions}, \textit{Promises})
|
|
\end{itemize}
|
|
|
|
\column{.2\textwidth}
|
|
\includegraphics[width=\columnwidth]{img/js.png}
|
|
\includegraphics[width=\columnwidth]{img/netscape.png}
|
|
\includegraphics[width=\columnwidth]{img/nodejs.png}
|
|
\end{columns}
|
|
\end{frame}
|
|
|
|
\begin{frame}
|
|
\begin{columns}
|
|
\column{.6\textwidth}
|
|
\centering
|
|
\includegraphics[width=.9\columnwidth]{img/jetbrains-ecosystem-2025-evolution.png}
|
|
|
|
\column{.4\textwidth}
|
|
\begin{itemize}
|
|
\item \textit{"Among the most dramatic rises in real-world usage over the last five years is TypeScript."}
|
|
\end{itemize}
|
|
\end{columns}
|
|
\end{frame}
|
|
|
|
\begin{frame}
|
|
\centering
|
|
\includegraphics[width=.7\columnwidth]{img/jetbrains-ecosystem-2025-platforms.png}
|
|
|
|
\footnote[]{\url{https://devecosystem-2025.jetbrains.com/tools-and-trends}}
|
|
\end{frame}
|
|
|
|
\begin{frame}{TypeScript}
|
|
\begin{itemize}
|
|
\item Conçu en 2012 par Anders Hejlsberg
|
|
\item Open source, maintenu par Microsoft
|
|
\item Ni interprété, ni compilé : langage \textbf{transpilé} vers JavaScript, \textit{superset} de JS
|
|
\item Exécutable dans n'importe quel \textit{runtime} JS (navigateur, Node.js, etc.)
|
|
\item Multi-paradigme : \textbf{fonctionnel}, générique, impératif, orienté objet
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}{TypeScript}
|
|
\begin{columns}
|
|
\column{.8\textwidth}
|
|
\begin{itemize}
|
|
\item \textbf{Typage statique} : détecter les erreurs et incohérences à la compilation (donc avant l'exécution)
|
|
\item \textbf{Interopérabilité} : typage \textit{progressif} (tout fichier JavaScript valide est un fichier TypeScript valide)
|
|
\end{itemize}
|
|
|
|
\column{.2\textwidth}
|
|
\includegraphics[width=\columnwidth]{img/ts.png}
|
|
\end{columns}
|
|
|
|
Adoption par l'industrie :
|
|
\begin{itemize}
|
|
\item Slack~\footnote[frame]{\url{https://slack.engineering/typescript-at-slack/}} : migration du frontend React vers TS pour sécuriser les appels d'API et réduire les erreurs au runtime
|
|
\item Airbnb~\footnote[frame]{\url{https://www.youtube.com/watch?v=P-J9Eg7hJwE}} : typage progressif du code JS pour réduire les coûts de maintenance
|
|
\item Microsoft~\footnote[frame]{\url{https://www.git-tower.com/blog/developing-for-the-desktop-vscode}} : migration vers TS pour faciliter l'évolution de VS Code ($>$ 1M SLoC)
|
|
\item Shopify~\footnote[frame]{\url{https://shopify.engineering/migrating-large-typescript-codebases-project-references}} : migration frontend et backend pour fiabiliser les fonctions critiques
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}{TypeScript}
|
|
\begin{itemize}
|
|
\item Ressources :
|
|
\begin{itemize}
|
|
\item \textit{The TypeScript Handbook}~\footnote{\fullcite{HandbookTypeScriptHandbook}}
|
|
\item \textit{The Concise TypeScript Book}~\footnote{\fullcite{poggialiConciseTypeScriptBook2026}}
|
|
\item TypeScript TV~\footnote[frame]{\url{https://typescript.tv/}} (liste des codes d'erreur)
|
|
\item TS Playground~\footnote[frame]{\url{https://www.typescriptlang.org/play/}} (environnement d'exécution en ligne)
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}{TypeScript : typage du code JavaScript}
|
|
Types de base disponibles dans TypeScript~\footnote{\url{https://www.typescriptlang.org/docs/handbook/2/everyday-types.html}} :
|
|
\begin{itemize}
|
|
\item \texttt{boolean}
|
|
\item \texttt{number}
|
|
\item \texttt{string}
|
|
\item Tableaux (dynamiques) -- exemple : \texttt{string[]} ou \texttt{Array<string>}
|
|
\item Tuples (taille fixe) -- exemple : \texttt{let x: [string, number]}
|
|
\item \texttt{enum}
|
|
\item \texttt{unknown} (type à préciser en le vérifiant à l'exécution)
|
|
\item \texttt{any} (à éviter : toute valeur autorisée)
|
|
\item \texttt{void} (absence de valeur)
|
|
\item \texttt{null} (valeur vide) et \texttt{undefined} (valeur non définie)
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 1 : les pièges du typage dynamique}
|
|
\begin{block}{Fonctions et paramètres}
|
|
\begin{itemize}
|
|
\item Écrire une fonction \texttt{addition(a, b)} qui additionne deux nombres.
|
|
\item Tester la fonction avec les entrées suivantes :
|
|
\end{itemize}
|
|
\end{block}
|
|
|
|
\begin{minted}{js}
|
|
addition(2, 3); // attendu : 5
|
|
addition("2", 3); // attendu : ?
|
|
addition(true, 3); // attendu : ?
|
|
\end{minted}
|
|
|
|
\begin{alertblock}{Questions}
|
|
\begin{enumerate}
|
|
\item Que se passe-t-il pour les deux derniers cas ?
|
|
\item Quels problèmes cela pose-t-il poser dans une application réelle ?
|
|
\item Proposer une version TypeScript pour éviter ces erreurs \textit{à la compilation}.
|
|
\end{enumerate}
|
|
\end{alertblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 1 : les pièges du typage dynamique}
|
|
\begin{minted}{ts}
|
|
function addition2(a: number, b: number): number {
|
|
return a + b;
|
|
}
|
|
|
|
console.log(addition2(2, 3));
|
|
// L'argument de type 'string' n'est pas attribuable au paramètre
|
|
// de type 'number'.ts(2345)
|
|
console.log(addition2("2", 3));
|
|
// L'argument de type 'boolean' n'est pas attribuable au paramètre
|
|
// de type 'number'.ts(2345)
|
|
console.log(addition2(true, 3));
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{JavaScript : POJO (\textit{Plain Old Java Object})}
|
|
\begin{minted}{js}
|
|
const o = {
|
|
"foo": "bar",
|
|
"value": 42,
|
|
other: true,
|
|
}
|
|
|
|
console.log(o.foo);
|
|
console.log(o["value"]);
|
|
console.log(o.other);
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{TypeScript : typer les objets avec \texttt{Record}}
|
|
\begin{minted}{js}
|
|
const o: Record<string, string | number | boolean> = {
|
|
"foo": "bar",
|
|
"value": 42,
|
|
other: true,
|
|
}
|
|
|
|
console.log(o.foo);
|
|
console.log(o["value"]);
|
|
console.log(o.other);
|
|
console.log(o.blabla); // undefined
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Typage, interfaces et classes}
|
|
\begin{columns}
|
|
\column{.5\textwidth}
|
|
\begin{minted}{ts}
|
|
// Définition
|
|
interface Bidule {
|
|
truc: string;
|
|
machin: number;
|
|
toto?: boolean;
|
|
}
|
|
|
|
// Instanciation
|
|
const b: Bidule = {
|
|
truc: "bidule",
|
|
machin: 42,
|
|
};
|
|
\end{minted}
|
|
|
|
\column{.5\textwidth}
|
|
\begin{minted}{ts}
|
|
// Définition
|
|
class Bidule {
|
|
constructor(
|
|
public truc: string,
|
|
public machin: number,
|
|
public toto?: boolean,
|
|
) {}
|
|
}
|
|
|
|
// Instanciation
|
|
const b: Bidule = new Bidule(
|
|
"bidule", 42
|
|
);
|
|
\end{minted}
|
|
\end{columns}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 2 : interfaces et contrats}
|
|
\begin{block}{Typage des objets}
|
|
\begin{itemize}
|
|
\item Écrire une fonction \texttt{afficherUtilisateur(u)} qui prend un objet représentant un utilisateur et affiche son nom et son âge.
|
|
\item Tester la fonction avec les entrées suivantes :
|
|
\end{itemize}
|
|
\end{block}
|
|
|
|
\begin{minted}{js}
|
|
afficherUtilisateur({ nom: "Alice", age: 25 });
|
|
afficherUtilisateur({ nom: "Bob" });
|
|
\end{minted}
|
|
|
|
\begin{alertblock}{Questions}
|
|
\begin{enumerate}
|
|
\item Que se passe-t-il pour le second cas ?
|
|
\item Comment TypeScript peut-il garantir la présence des propriétés attendues ?
|
|
\item Proposer une solution avec TypeScript.
|
|
\end{enumerate}
|
|
\end{alertblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 2 : interfaces et contrats}
|
|
\begin{minted}{ts}
|
|
interface Utilisateur {
|
|
nom: string;
|
|
age: number;
|
|
}
|
|
|
|
function afficherUtilisateur(u: Utilisateur): void {
|
|
console.log(`${u.nom} a ${u.age} ans`);
|
|
}
|
|
|
|
afficherUtilisateur({ nom: "Alice", age: 25 });
|
|
// L'argument de type '{ nom: string; }' n'est pas attribuable
|
|
// au paramètre de type 'Utilisateur'.
|
|
// La propriété 'age' est absente du type '{ nom: string; }'
|
|
// mais obligatoire dans le type 'Utilisateur'.ts(2345)
|
|
afficherUtilisateur({ nom: "Bob" });
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Typage, interfaces et classes}
|
|
\begin{itemize}
|
|
\item Types \textbf{effacés} à la compilation
|
|
\begin{itemize}
|
|
\item Pas d'impact sur les performances (compromis : temps de compilation vs temps d'exécution)
|
|
\item Une erreur de typage n'empêche pas la compilation vers JavaScript
|
|
\end{itemize}
|
|
\item Corollaire : il n'est pas possible de vérifier les types TypeScript \textbf{lors de l'exécution} du programme...
|
|
\item ... sauf pour les types primitifs de JavaScript !
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Typage, interfaces et classes}
|
|
\begin{minted}{ts}
|
|
// type union : soit number, soit string
|
|
const fn = (x: number | string) => {
|
|
// typeof type guard
|
|
if (typeof x === 'number') {
|
|
return x + 1;
|
|
}
|
|
|
|
return -1;
|
|
};
|
|
\end{minted}
|
|
|
|
\begin{minted}{ts}
|
|
// type union : soit string, soit null
|
|
const toUpperCase = (name: string | null) => {
|
|
// truthiness narrowing
|
|
if (name) {
|
|
return name.toUpperCase();
|
|
} else {
|
|
return null;
|
|
}
|
|
};
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 3 : types au \textit{runtime}}
|
|
\begin{minted}[fontsize=\footnotesize]{ts}
|
|
interface Animal {
|
|
name: string;
|
|
}
|
|
interface Dog extends Animal {
|
|
bark: () => void;
|
|
}
|
|
interface Cat extends Animal {
|
|
meow: () => void;
|
|
}
|
|
const makeNoise = (animal: Animal) => {
|
|
if (animal instanceof Dog) {
|
|
// 'Dog' fait référence à un type mais s'utilise en tant que valeur ici.ts(2693)
|
|
animal.bark();
|
|
} else {
|
|
animal.meow();
|
|
}
|
|
};
|
|
\end{minted}
|
|
|
|
\begin{alertblock}{Questions}
|
|
\begin{enumerate}
|
|
\item Que signifie l'erreur levée par le compilateur ?
|
|
\item Comment peut-on vérifier la nature de l'objet \texttt{animal} au \textit{runtime} ?
|
|
\end{enumerate}
|
|
\end{alertblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 3 : types au \textit{runtime}}
|
|
\begin{minted}{ts}
|
|
interface Dog {
|
|
kind: "dog"; // Tagged union
|
|
bark: () => void;
|
|
}
|
|
|
|
interface Cat {
|
|
kind: "cat"; // Tagged union
|
|
meow: () => void;
|
|
}
|
|
|
|
type Animal = Dog | Cat; // Union type
|
|
|
|
const makeNoise = (animal: Animal) => {
|
|
if (animal.kind === "dog") animal.bark();
|
|
else animal.meow();
|
|
};
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 3 : types au \textit{runtime}}
|
|
\begin{minted}{ts}
|
|
class Dog {
|
|
constructor(public name: string, public bark: () => void) {}
|
|
}
|
|
|
|
class Cat {
|
|
constructor(public name: string, public meow: () => void) {}
|
|
}
|
|
|
|
type Animal = Dog | Cat; // Union type
|
|
|
|
const makeNoise = (animal: Animal) => {
|
|
if (animal instanceof Dog) animal.bark();
|
|
else animal.meow();
|
|
};
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Généricité}
|
|
\begin{itemize}
|
|
\item \texttt{SomeContainer<T extends SomeData>}
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 3 : types au \textit{runtime}}
|
|
\begin{minted}[fontsize=\footnotesize]{ts}
|
|
interface Dog {
|
|
kind: "dog"; // Tagged union
|
|
bark: () => void;
|
|
}
|
|
interface Cat {
|
|
kind: "cat"; // Tagged union
|
|
meow: () => void;
|
|
}
|
|
type Animal = Dog | Cat;
|
|
const makeNoise = (animal: Animal) => {
|
|
if (animal.kind === "dog") animal.bark();
|
|
else animal.meow();
|
|
};
|
|
const dog: Dog = {
|
|
kind: "dog",
|
|
bark: () => console.log("bark")
|
|
};
|
|
makeNoise(dog);
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Gestion des erreurs : exceptions}
|
|
\begin{itemize}
|
|
\item Exceptions
|
|
\item \texttt{try}/\texttt{catch}
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Programmation asynchrone}
|
|
TODO: Exemple (requête API) avec figure
|
|
|
|
Comment manipuler des données...
|
|
\begin{itemize}
|
|
\item que l'on n'a pas encore ?
|
|
\item que l'on n'aura peut-être jamais ?
|
|
\item qui l'on obtient dans un temps variable ?
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Programmation asynchrone}
|
|
\begin{itemize}
|
|
\item API : \textbf{Promises}
|
|
\begin{itemize}
|
|
\item Traiter des opérations \textbf{asynchrones}
|
|
\item Une Promise \textit{encapsule un résultat futur}
|
|
\item Elle est associée à des \textit{callbacks} qui seront exécutés à l'obtention de ce résultat
|
|
\item Elle peut être \textit{résolue} (réussite) ou \textit{rejetée} (échec)
|
|
\end{itemize}
|
|
\end{itemize}
|
|
|
|
\centering
|
|
\includegraphics[width=.8\textwidth]{img/promises.png}
|
|
|
|
\footnote[]{\url{https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise}}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Programmation asynchrone}
|
|
\begin{minted}[fontsize=\footnotesize]{ts}
|
|
function repeatMaybe(repeat: string): Promise<string> {
|
|
return new Promise((resolve, reject) => {
|
|
const maybe: number = randomIntegerBetween(0, 1);
|
|
|
|
if (!maybe) {
|
|
reject("Nope");
|
|
return;
|
|
}
|
|
|
|
setTimeout(() => {
|
|
resolve(repeat);
|
|
}, 1000);
|
|
});
|
|
}
|
|
|
|
const blabla = repeatMaybe("bla").then((result: string) => {
|
|
console.log(result);
|
|
}).catch((error: string) => {
|
|
console.log(error)
|
|
});
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Programmation asynchrone}
|
|
\begin{columns}
|
|
\column{.5\textwidth}
|
|
\begin{itemize}
|
|
\item API : \texttt{async}/\texttt{await}
|
|
\begin{itemize}
|
|
\item Sucre syntaxique pour "aplatir" du code asynchrone
|
|
\item \texttt{async} définit une fonction asynchrone
|
|
\item \texttt{await} met l'exécution du programme en pause dans l'attente d'un résultat
|
|
\end{itemize}
|
|
\end{itemize}
|
|
|
|
\column{.5\textwidth}
|
|
\centering
|
|
\includegraphics[width=.7\columnwidth]{img/async-joke.jpg}
|
|
\end{columns}
|
|
|
|
\vspace{1cm}
|
|
|
|
\begin{columns}
|
|
\column{.5\textwidth}
|
|
\begin{minted}[fontsize=\footnotesize]{ts}
|
|
asyncFunction().then((res) => {
|
|
console.log(res);
|
|
}).catch((err) => {
|
|
console.log(err);
|
|
});
|
|
\end{minted}
|
|
|
|
\column{.5\textwidth}
|
|
\begin{minted}[fontsize=\footnotesize]{ts}
|
|
try {
|
|
const res = await asyncFunction();
|
|
console.log(res); // "bla"
|
|
} catch (err) {
|
|
console.log(err); // "Nope"
|
|
}
|
|
\end{minted}
|
|
\end{columns}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Programmation asynchrone}
|
|
\begin{minted}[fontsize=\footnotesize]{ts}
|
|
function repeatMaybe(repeat: string): Promise<string> {
|
|
return new Promise((resolve, reject) => {
|
|
const maybe: number = randomIntegerBetween(0, 1);
|
|
|
|
if (!maybe) {
|
|
reject("Nope");
|
|
return;
|
|
}
|
|
|
|
setTimeout(() => {
|
|
resolve(repeat);
|
|
}, 1000);
|
|
});
|
|
}
|
|
|
|
try {
|
|
const blabla = await repeatMaybe("bla");
|
|
console.log(blabla); // "bla"
|
|
} catch (error) {
|
|
console.log(error); // "Nope"
|
|
}
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Programmation parallèle}
|
|
\begin{itemize}
|
|
\item \texttt{Promise.all}
|
|
\item \texttt{Promise.allSettled}
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 4 : programmation asynchrone}
|
|
\begin{block}{Manipuler l'API Promise}
|
|
\begin{itemize}
|
|
\item Écrire une fonction \texttt{readTextFileIfExists(path)} qui lit un fichier s'il existe et retourne son contenu si le fichier n'est pas vide :
|
|
\end{itemize}
|
|
\end{block}
|
|
|
|
\begin{minted}{js}
|
|
readTextFileIfExists("data.txt")
|
|
.then(text => console.log("File contents:", text))
|
|
.catch(err => console.error("I/O error:", err.message));
|
|
\end{minted}
|
|
|
|
\begin{alertblock}{Questions}
|
|
\begin{enumerate}
|
|
\item Quelle est la signature de cette fonction en TypeScript ?
|
|
\item Comment utiliser cette fonction avec \texttt{await} ?
|
|
\item Comment utiliser cette fonction sur une liste de fichiers ?
|
|
\item Comment paralléliser la lecture des fichiers de la liste ?
|
|
\end{enumerate}
|
|
\end{alertblock}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 4 : programmation asynchrone}
|
|
\begin{minted}[fontsize=\footnotesize]{js}
|
|
function readTextFileIfExists(path) {
|
|
return new Promise((resolve, reject) => {
|
|
if (!path) {
|
|
reject(new Error("No file path provided"));
|
|
return;
|
|
}
|
|
|
|
readFile(path, "utf8")
|
|
.then(data => {
|
|
if (data.length === 0) {
|
|
reject(new Error("File is empty")); // explicit failure
|
|
} else {
|
|
resolve(data); // successful read
|
|
}
|
|
})
|
|
.catch(err => reject(err)); // I/O error
|
|
});
|
|
}
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 4 : programmation asynchrone}
|
|
\begin{minted}{js}
|
|
try {
|
|
const text = await readTextFileIfExists("data.txt");
|
|
console.log("File contents:", text);
|
|
} catch (err) {
|
|
console.error("I/O error:", err.message);
|
|
}
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 4 : programmation asynchrone}
|
|
\begin{minted}{js}
|
|
const files = ["file1.txt", "file2.txt", "file3.txt"];
|
|
|
|
for (const file of files) {
|
|
try {
|
|
const text = await readTextFileIfExists(file);
|
|
console.log("File contents:", text);
|
|
} catch (err) {
|
|
console.error("I/O error:", err.message);
|
|
continue;
|
|
}
|
|
}
|
|
\end{minted}
|
|
|
|
\vspace{.5cm}
|
|
|
|
\begin{block}{\emoji{thinking}}
|
|
Temps d'exécution total = ?
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 4 : programmation asynchrone}
|
|
\begin{minted}{js}
|
|
const files = ["does_not_exist.txt", "file2.txt", "file3.txt"];
|
|
|
|
const contents = await Promise.all(
|
|
files.map(readTextFileIfExists)
|
|
);
|
|
try {
|
|
contents.forEach((text, i) => {
|
|
console.log("File contents:", text);
|
|
});
|
|
} catch (err) {
|
|
console.error("I/O error:", err.message);
|
|
}
|
|
\end{minted}
|
|
|
|
\vspace{.5cm}
|
|
|
|
\begin{block}{\emoji{thinking}}
|
|
Temps d'exécution total = ?
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 4 : programmation asynchrone}
|
|
\begin{minted}{js}
|
|
const files = ["does_not_exist.txt", "file2.txt", "file3.txt"];
|
|
|
|
const contents = await Promise.allSettled(
|
|
files.map(readTextFileIfExists)
|
|
);
|
|
contents.forEach((result, i) => {
|
|
if (result.status === "fulfilled") {
|
|
console.log("File contents:", result.value);
|
|
} else if (result.status === "rejected") {
|
|
console.error("I/O error:", result.reason);
|
|
}
|
|
});
|
|
\end{minted}
|
|
|
|
\vspace{.5cm}
|
|
|
|
\begin{block}{\emoji{thinking}}
|
|
Temps d'exécution total = ?
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Exécution : machine virtuelle}
|
|
\begin{itemize}
|
|
\item JavaScript : langage interprété dans une VM
|
|
\item Langage permet d'exprimer des instructions \textbf{asynchrones}
|
|
\item Runtime \textbf{synchrone} : boucle d'événements (pas de coroutines, pas de threads~\footnote{Sauf \textit{workers}, voir~\url{https://developer.mozilla.org/en-US/docs/Glossary/Thread}})
|
|
\end{itemize}
|
|
|
|
\centering
|
|
\includegraphics[width=\textwidth]{img/js-event-loop.png}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Runtime : Deno}
|
|
\begin{columns}
|
|
\column{.8\textwidth}
|
|
\begin{itemize}
|
|
\item Runtime pour exécuter du code JavaScript en-dehors du navigateur
|
|
\item Basé sur le moteur V8 (comme Node.js)
|
|
\item Créé en 2018 par Ryan Dahl, développeur de Node.js~\footnote[frame]{\url{https://www.youtube.com/watch?v=M3BM9TB-8yA}}
|
|
\item Points forts :
|
|
\begin{itemize}
|
|
\item \textit{Sandbox} : permissions explicites (lecture/écriture, accès au réseau, etc.)
|
|
\item Exécute du code TypeScript sans outillage supplémentaire
|
|
\item Inclut un formateur, un \textit{linter}, une plateforme de test, un profileur
|
|
\end{itemize}
|
|
\end{itemize}
|
|
|
|
\column{.2\textwidth}
|
|
\includegraphics[width=\columnwidth]{img/deno.png}
|
|
\end{columns}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Sécurité, permissions}
|
|
\begin{itemize}
|
|
\item \textit{Supply-chain attack} : introduction de vulnérabilités dans un logiciel \textit{via} compromission d'une ou plusieurs de ses dépendances
|
|
\item Exemple : \textit{Shai Hulud}, novembre 2025~\footnote[frame]{\url{https://www.cert.ssi.gouv.fr/actualite/CERTFR-2025-ACT-051/}}, 700 paquets compromis sur NPM
|
|
\begin{itemize}
|
|
\item récupération de différents secrets présents sur la machine compromise [...] ;
|
|
\item exfiltration des secrets ;
|
|
\item réplication par l'infection de paquets NPM ;
|
|
\item suppression de données utilisateurs ;
|
|
\item mise en place de persistance.
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Gestion des dépendances}
|
|
\begin{columns}
|
|
\column{.8\textwidth}
|
|
Outils (npm, etc.)
|
|
|
|
Modules (ESM vs CommonJS) et imports
|
|
|
|
\column{.2\textwidth}
|
|
\includegraphics[width=\columnwidth]{img/npm.png}
|
|
\includegraphics[width=\columnwidth]{img/jsr.png}
|
|
\end{columns}
|
|
\end{frame}
|
|
|
|
\section{Serveur web}
|
|
|
|
\begin{frame}{HTTP}
|
|
\centering
|
|
\includegraphics[width=.6\textwidth]{img/series-of-tubes.png}
|
|
\end{frame}
|
|
|
|
\begin{frame}{HTTP}
|
|
\begin{columns}
|
|
\column{.6\textwidth}
|
|
\begin{itemize}
|
|
\item \textit{Hypertext Transfer Protocol} : à l'origine, sert à partager des pages web reliées entre elles par des liens
|
|
\item Inventé au CERN~\footnote[frame]{Initialement \textit{Conseil européen pour la recherche nucléaire}, plus grand centre de recherche au monde en physique des particules} par un chercheur britannique, Tim Berners-Lee, entre 1989 et 1991
|
|
\item 1997 : standardisation de HTTP/1.1 :
|
|
\begin{itemize}
|
|
\item Apparition de l'en-tête \texttt{Host}, permettant d'héberger plusieurs domaines sur la même adresse IP, donc la colocation de serveurs web
|
|
\end{itemize}
|
|
\end{itemize}
|
|
|
|
\begin{center}
|
|
\includegraphics[width=.4\columnwidth]{img/tbl.jpg}
|
|
\end{center}
|
|
|
|
\column{.4\textwidth}
|
|
\includegraphics[width=\columnwidth]{img/osi-model.png}
|
|
\end{columns}
|
|
\end{frame}
|
|
|
|
\begin{frame}{HTTP : requêtes et réponses}
|
|
\centering
|
|
\includegraphics[width=\textwidth]{img/http-message.png}
|
|
\end{frame}
|
|
|
|
\begin{frame}{HTTP : méthodes}
|
|
Méthodes principales pour les requêtes HTTP~\footnote[frame]{\url{https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods}}, aussi appelées \textit{verbes} :
|
|
|
|
\begin{itemize}
|
|
\item \texttt{GET} : demande d'une ressource
|
|
\item \texttt{POST} : envoi de données du \textit{corps} de la requête vers une ressource
|
|
\item \texttt{PUT} : remplacement d'une ressource par le \textit{corps} de la requête
|
|
\item \texttt{DELETE} : suppression d'une ressource
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}{HTTP : codes de réponse}
|
|
\begin{itemize}
|
|
\item \texttt{100} à \texttt{199} : réponses informatives
|
|
\begin{itemize}
|
|
\item \texttt{101 Switching Protocols}
|
|
\end{itemize}
|
|
\item \texttt{200} à \texttt{299} : réponses de succès
|
|
\begin{itemize}
|
|
\item \texttt{200 OK}
|
|
\end{itemize}
|
|
\item \texttt{300} à \texttt{399} : réponses de redirection
|
|
\begin{itemize}
|
|
\item \texttt{301 Moved Permanently}
|
|
\end{itemize}
|
|
\item \texttt{400} à \texttt{499} : erreurs du client
|
|
\begin{itemize}
|
|
\item \texttt{401 Unauthorized}
|
|
\end{itemize}
|
|
\item \texttt{500} à \texttt{599} : erreurs du serveur
|
|
\begin{itemize}
|
|
\item \texttt{500 Internal Server Error}
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 5 : un serveur HTTP minimal avec TypeScript}
|
|
\begin{block}{Lire et écrire sur un socket TCP}
|
|
Ci-dessous, la boucle principale pour ouvrir et écouter sur un socket TCP avec Deno. Dès la connexion d'un \textbf{client}, on passe le socket à la fonction \texttt{handleConn}.
|
|
\end{block}
|
|
|
|
\begin{minted}{ts}
|
|
// TCP socket
|
|
const listener = Deno.listen({ port: 8080 });
|
|
// Strings <-> Bytes
|
|
const decoder = new TextDecoder();
|
|
const encoder = new TextEncoder();
|
|
// Listen loop
|
|
for await (const conn of listener) {
|
|
handleConn(conn);
|
|
}
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 5 : un serveur HTTP minimal avec TypeScript}
|
|
\begin{block}{Lire et écrire sur un socket TCP}
|
|
Ci-dessous, la fonction \texttt{handleConn} par laquelle chaque \textbf{requête} en provenance d'un \textbf{client} est traitée. Le serveur reçoit un \textbf{tableau d'octets} ; on le convertit en une chaîne de caractères dans \texttt{rawRequest}.
|
|
\end{block}
|
|
|
|
\begin{minted}{ts}
|
|
async function handleConn(conn: Deno.Conn) {
|
|
const buf = new Uint8Array(1024);
|
|
const bytes = await conn.read(buf);
|
|
if (bytes === null) {
|
|
conn.close();
|
|
return;
|
|
}
|
|
|
|
const rawRequest = decoder.decode(buf.subarray(0, bytes));
|
|
}
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Exercice 5 : un serveur HTTP minimal avec TypeScript}
|
|
\begin{minted}{sh}
|
|
curl -X POST http://localhost:8080 \
|
|
-H "Content-Type: text/plain" \
|
|
--data "hello world"
|
|
\end{minted}
|
|
|
|
\vspace{1cm}
|
|
|
|
\begin{columns}
|
|
\column{.5\textwidth}
|
|
\begin{minted}{text}
|
|
POST / HTTP/1.1
|
|
Host: localhost:8080
|
|
User-Agent: curl/8.14.1
|
|
Accept: */*
|
|
Content-Type: text/plain
|
|
Content-Length: 11
|
|
|
|
hello world
|
|
\end{minted}
|
|
|
|
\column{.5\textwidth}
|
|
\begin{alertblock}{Questions}
|
|
\begin{enumerate}
|
|
\item Quels sont les champs à inclure dans la réponse que l'on va retourner au client ?
|
|
\item Compléter la fonction \texttt{handleConn} pour signifier une réponse OK comportant du texte au format JSON.
|
|
\item TODO: new Date().toUTCString();
|
|
\end{enumerate}
|
|
\end{alertblock}
|
|
\end{columns}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Framework pour serveur HTTP : Oak}
|
|
\begin{columns}
|
|
\column{.8\textwidth}
|
|
\begin{itemize}
|
|
\item Inspiré par Express.js, initialement développé pour Deno
|
|
\item Framework \textit{middleware} : un logiciel qui s'intercale entre la requête d'un client et la réponse d'un serveur
|
|
\item \textbf{Contexte} $=$ \textbf{Requête} $+$ \textbf{Réponse}
|
|
\item Mécanisme principal : le \textbf{routage}
|
|
\begin{itemize}
|
|
\item Pour un point d'entrée donné, appliquer telle fonction, retourner telle valeur
|
|
\item Requête : \texttt{GET http://blabla.com/item/123}
|
|
\item Route : \texttt{/item/:itemId}
|
|
\item Fonction : \texttt{getItem(id)}
|
|
\item Réponse : \texttt{\{ id: 123, value: "..." \}}
|
|
\end{itemize}
|
|
\end{itemize}
|
|
|
|
\column{.2\textwidth}
|
|
\includegraphics[width=\columnwidth]{img/oak.png}
|
|
\end{columns}
|
|
\end{frame}
|
|
|
|
\begin{frame}{JSON}
|
|
|
|
\end{frame}
|
|
|
|
\begin{frame}{Middleware}
|
|
|
|
\end{frame}
|
|
|
|
\begin{frame}{Middleware : CORS}
|
|
TODO: à mettre côté client ?
|
|
\end{frame}
|
|
|
|
\begin{frame}{Middleware : Gestion des erreurs}
|
|
|
|
\end{frame}
|
|
|
|
\begin{frame}{Base de données}
|
|
\begin{columns}
|
|
\column{.8\textwidth}
|
|
\begin{itemize}
|
|
\item SQLite
|
|
\item Interactions avec SQLite : bibliothèque
|
|
\item Conversion des \textbf{enregistrements} vers des \textbf{objets}
|
|
\end{itemize}
|
|
|
|
\column{.2\textwidth}
|
|
\includegraphics[width=\columnwidth]{img/sqlite.png}
|
|
\end{columns}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Base de données : rappels sur SQL}
|
|
\begin{minted}{sql}
|
|
CREATE TABLE things (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
maybe TEXT,
|
|
active INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE TABLE thing_options (
|
|
id TEXT PRIMARY KEY,
|
|
thing_id TEXT NOT NULL,
|
|
value TEXT NOT NULL,
|
|
FOREIGN KEY (thing_id) REFERENCES things(id) ON DELETE CASCADE
|
|
);
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Base de données : transactions}
|
|
\begin{itemize}
|
|
\item \textbf{Interdépendance} (sémantique et/ou fonctionnelle) entre deux requêtes \textbf{distinctes}
|
|
\item Les deux doivent réussir ou échouer \textbf{ensemble} pour éviter une \textbf{incohérence dans l'état} de l'application
|
|
\end{itemize}
|
|
|
|
\vspace{.5cm}
|
|
|
|
\begin{minted}[fontsize=\footnotesize]{ts}
|
|
// Persist vote
|
|
const voteId = crypto.randomUUID();
|
|
const now = new Date().toISOString();
|
|
db.prepare(
|
|
"INSERT INTO votes " +
|
|
"(id, poll_id, option_id, user_id, created_at) " +
|
|
"VALUES (?, ?, ?, ?, ?);",
|
|
).run(voteId, pollId, optionId, userId || null, now);
|
|
|
|
// Increment tally
|
|
db.prepare(
|
|
"UPDATE poll_options SET vote_count = vote_count + 1 WHERE id = ?;",
|
|
).run(optionId);
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Base de données : transactions}
|
|
\begin{itemize}
|
|
\item Mécanisme : \textbf{transactions}
|
|
\item Unités de travail qui garantissent l'\textbf{atomicité} des opérations
|
|
\end{itemize}
|
|
|
|
\vspace{.5cm}
|
|
|
|
\begin{minted}{ts}
|
|
try {
|
|
db.prepare("BEGIN").run(); // Start transaction
|
|
|
|
db.prepare("...").run(); // Query 1
|
|
db.prepare("...").run(); // Query 2
|
|
|
|
db.prepare("COMMIT").run(); // Commit transaction
|
|
} catch {
|
|
db.prepare("ROLLBACK").run(); // Rollback on any error
|
|
}
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Tests}
|
|
\begin{minted}{ts}
|
|
import { assertEquals, assert } from "@std/assert";
|
|
|
|
const BASE_URL = `http://localhost:8000`;
|
|
|
|
Deno.test({
|
|
name: "polls management API",
|
|
async fn() {
|
|
const listRes = await fetch(`${BASE_URL}/polls`);
|
|
assertEquals(listRes.status, 200);
|
|
|
|
const listBody = await listRes.json();
|
|
assert(listBody.success);
|
|
assert(listBody.data.length >= 1);
|
|
},
|
|
});
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\section{Client web}
|
|
|
|
\begin{frame}{HTTP, encore}
|
|
\begin{itemize}
|
|
\item API \texttt{fetch}
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Un client web minimal avec TypeScript}
|
|
\begin{minted}{js}
|
|
const foo = "bar";
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Framework : React}
|
|
\begin{itemize}
|
|
\item Hooks
|
|
\begin{itemize}
|
|
\item \texttt{useParams}
|
|
\item \texttt{useState}
|
|
\item \texttt{useRef}
|
|
\item \texttt{useEffect}
|
|
\end{itemize}
|
|
\item Functional Components
|
|
\item React Router
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Bundling}
|
|
\begin{itemize}
|
|
\item Bundler
|
|
\item Vite
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}{React : architecture}
|
|
\begin{itemize}
|
|
\item Service Layer Pattern
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Bundler}
|
|
|
|
\end{frame}
|
|
|
|
\section{Authentification}
|
|
|
|
\begin{frame}{Concepts généraux}
|
|
|
|
\end{frame}
|
|
|
|
\begin{frame}{\textit{Stateful} : Sessions}
|
|
|
|
\end{frame}
|
|
|
|
\begin{frame}{\textit{Stateless} : JWT}
|
|
|
|
\end{frame}
|
|
|
|
\section{Interactions}
|
|
|
|
\begin{frame}{REST}
|
|
|
|
\end{frame}
|
|
|
|
\begin{frame}{Data Transfer Objects}
|
|
|
|
\end{frame}
|
|
|
|
\begin{frame}{WebSockets}
|
|
|
|
\end{frame}
|
|
|
|
\section{Déploiement de l'application}
|
|
|
|
\begin{frame}{Nom d'hôte, port, adresse}
|
|
\begin{center}
|
|
\texttt{%
|
|
{\color{BrickRed}https}://%
|
|
{\color{MidnightBlue}foo.bar}.%
|
|
{\color{Orchid}com}%
|
|
[:{\color{LimeGreen}443}]/%
|
|
{\color{YellowOrange}baz.html}%
|
|
}
|
|
\end{center}
|
|
|
|
\begin{center}
|
|
\includegraphics[width=.5\textwidth]{img/brace.png}
|
|
\end{center}
|
|
|
|
\begin{itemize}
|
|
\item \texttt{{\color{BrickRed}https}} : protocole
|
|
\item \texttt{{\color{MidnightBlue}foo.bar}} : nom d'hôte (\textit{hostname})
|
|
\item \texttt{{\color{Orchid}com}} : \textit{TLD} (\textit{Top-Level Domain})
|
|
\item \texttt{{\color{LimeGreen}443}} : port (HTTP : 80, HTTPS : 443)
|
|
\item \texttt{{\color{YellowOrange}baz.html}} : nom de fichier
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Reverse proxy}
|
|
\begin{minted}[fontsize=\footnotesize]{text}
|
|
http {
|
|
server {
|
|
listen 80;
|
|
server_name coucou.localhost;
|
|
|
|
location / {
|
|
proxy_pass http://127.0.0.1:8000;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
}
|
|
}
|
|
}
|
|
\end{minted}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Certificats SSL}
|
|
\begin{itemize}
|
|
\item Protocole (TLSv1.2, TLSv1.3)
|
|
\item Algorithme de chiffrement : AES 128/256, etc.
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\section{Débuggage et profilage}
|
|
|
|
\begin{frame}{Côté serveur}
|
|
\begin{columns}
|
|
\column{.5\textwidth}
|
|
\begin{itemize}
|
|
\item \texttt{deno run --v8-flags="--prof" main.ts}
|
|
\begin{itemize}
|
|
\item Crée un fichier .log dans le répertoire courant
|
|
\item \textit{"V8 has built-in sample-based profiling. Profiling is turned off by default, but can be enabled via the \texttt{--prof} command-line option. The sampler records stacks of both JavaScript and C/C++ code."}
|
|
\end{itemize}
|
|
\item Lecture du fichier avec cpupro~\footnote[frame]{\url{https://discoveryjs.github.io/cpupro/}}
|
|
\begin{itemize}
|
|
\item Visualisation : \textit{flame graph}~\footnote[frame]{\fullcite{greggFlameGraph2016}}
|
|
\end{itemize}
|
|
\end{itemize}
|
|
|
|
\column{.5\textwidth}
|
|
\includegraphics[width=\columnwidth]{img/flamegraph.png}
|
|
\end{columns}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Côté client}
|
|
|
|
\end{frame}
|
|
|
|
\appendix
|
|
|
|
\section{Bibliographie}
|
|
|
|
\begin{frame}[allowframebreaks]{Références}
|
|
\printbibliography[heading=none]
|
|
\end{frame}
|
|
|
|
% \appendix
|
|
|
|
% \section{Annexes}
|
|
|
|
% \begin{frame}{Annexe 1 -- ...}
|
|
% \end{frame}
|
|
|
|
\end{document}
|