\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} \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 = { "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} \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 { 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 { 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}