\documentclass[12pt, a4paper]{article} \setlength{\parskip}{1em} \usepackage[T1]{fontenc} \usepackage[a4paper, margin=0.7in]{geometry} \usepackage[french]{babel} \usepackage{amsmath} \usepackage{amsfonts} \usepackage{mathtools} \usepackage{mathabx} \usepackage{listings} \usepackage{xcolor} \usepackage{float} \usepackage{cite} \usepackage{subcaption} \usepackage{wrapfig} \usepackage{svg} \usepackage{ragged2e} \usepackage[nottoc,numbib]{tocbibind} \usepackage{hyperref} \hypersetup{ colorlinks=true, linkcolor=blue, urlcolor=blue, citecolor=red, pdftitle={Adrien Burgun - Rapport de stage ST40 - A2022} } % From https://github.com/pinam45/utbm-latex-internship-report-covers % Requires xelatex to run (or maybe also lualatex) \usepackage{utbmcovers} % From https://tex.stackexchange.com/questions/89574/language-option-supported-in-listings \lstdefinelanguage{JavaScript}{ keywords={ typeof, new, abstract, class, interface, type, function, return, try, catch, finally, switch, case, break, var, let, const, if, else, for, while, in, of, do, true, false, null, undefined }, keywordstyle=\color{blue}\bfseries, ndkeywords={ export, implements, import, this, private, public, readonly, constructor, @Inject, @Injectable, @Controller, @Module }, ndkeywordstyle=\color{darkgray}\bfseries, identifierstyle=\color{black}, sensitive=false, comment=[l]{//}, morecomment=[s]{/*}{*/}, commentstyle=\color{purple}\ttfamily, stringstyle=\color{red}\ttfamily, morestring=[b]', morestring=[b]" } \lstdefinelanguage{hbs}{ morecomment=[s]{\{\{!}{!\}\}}, commentstyle=\color{purple}\ttfamily, stringstyle=\color{red}\ttfamily, morestring=[s]{\{\{}{\}\}}, } \definecolor{bgColor}{rgb}{0.95,0.94,0.92} \lstdefinestyle{JavaScript}{ backgroundcolor=\color{bgColor}, commentstyle=\color{gray}, keywordstyle=\color{magenta}, numberstyle=\tiny\color{gray}, stringstyle=\color{purple}, basicstyle=\footnotesize, breakatwhitespace=false, breaklines=true, captionpos=b, keepspaces=true, numbers=left, numbersep=5pt, showspaces=false, showstringspaces=false, showtabs=false, tabsize=2, language=JavaScript } \graphicspath{{build/figures/}{images/}} \newfontfamily{\Tahoma}{Tahoma} \newfontfamily{\SourceSans}{Source Sans Pro} % Looks like the font from google fonts has a different case, % so I'm stuck with scanning for existing fonts \IfFontExistsTF{Source Sans Pro SemiBold}{ \newfontfamily{\SourceSansSB}[UprightFont={* SemiBold}]{Source Sans Pro} }{ \IfFontExistsTF{Source Sans Pro Semi-Bold}{ \newfontfamily{\SourceSansSB}[UprightFont={* Semi-Bold}]{Source Sans Pro} }{ \newfontfamily{\SourceSansSB}[UprightFont={* Semibold}]{Source Sans Pro} } } \setmainfont{Source Sans Pro} % \newfontfamily{\ossb}[UprightFont={* Semibold}]{Open Sans} \newcommand{\entity}[1]{{\SourceSansSB #1}} \newcommand{\entityb}[1]{#1} \newcommand{\person}[2]{#1 #2} \newcommand{\term}[1]{\textit{#1}} \newcommand{\figref}[1]{[Figure~\ref{#1}]} \newcommand{\inputfig}[1]{\input{figures/#1}} \title{Rapport de stage ST40 - A2022} \author{Adrien Burgun} \date{Automne 2022} \setutbmfrontillustration{assets/priscilla-du-preez-BjhUu6BpUZA-unsplash} \setutbmtitle{Stage développeur full stack} \setutbmsubtitle{Rapport de stage ST40 - A2022} \setutbmstudent{BURGUN Adrien} \setutbmstudentdepartment{Département Informatique} \setutbmstudentpathway{} \setutbmcompany{Moment - T\&M} \setutbmcompanyaddress{3 boulevard Richard Lenoir\\75011 Paris} \setutbmcompanywebsite{\href{https://moment.tech/}{moment.tech}} \setutbmcompanytutor{PERRIN Pierre} \setutbmschooltutor{HOLWECK Frederic} % From https://moodle.utbm.fr/pluginfile.php/117803/mod_book/chapter/595/CARNET-A22-20220711.pdf \setutbmkeywords{Télécommunications - Informatique - Développement logiciel - Logiciel de gestion - Logiciel de réseaux} \setutbmabstract{ J'ai effectué mon stage ST40 au sein du département de développement full-stack de l'entreprise \entity{Moment}, une start-up française basée à Paris et fondée en 2013. \newline % TODO: check wording (maritime) Moment propose à ses clients des offres de divertissement pour l'aviation, le secteur maritime, les chemins de fer et plus récemment le domaine de la santé. Leur offre principale, \og Flymingo \fg, permet d'accéder aux divertissements directement depuis les appareils mobiles des passagers. \newline J'ai pu contribuer au développement de fonctionnalités pour la nouvelle offre déployée dans les cliniques de santé, à l'optimisation de l'application tournant sur des télévisions connectées et au maintien du code front-end. } \begin{document} % \maketitle \makeutbmfrontcover{} { \Tahoma \tableofcontents } \newpage \section{Présentation} \subsection{Présentation de l'entreprise} \entity{Moment} est une entreprise fondée en 2013, avec pour but de rendre l'expérience des voyageurs plus simple, plus plaisante et plus connectée \cite{momenttech}. Pour y parvenir, \entity{Moment} propose une plateforme digitale déployée dans les avions, les trains, les bateaux de croisière et plus récemment les cliniques de santé. Cette plateforme permet aux voyageurs de se connecter à un réseau wifi avec leurs propres appareils, et de profiter de divertissements directement sur ceux-cis. % TODO: récupérer le vrai nombre d'employés et de projets À ce jour, \entityb{Moment} s'apprête à compter 10 ans de travail dans ce domaine, et possède une trentaine d'employés. \entityb{Moment} a lancé une cinquantaine de projets, dans 15 pays, et ses produits sont utilisés par plus de 10 millions de passagers par jour. % TODO: valider Air France? \entityb{Moment} fournit ses services aujourd'hui à \entity{Air France}, l'\entity{Aéroport de Paris}, \entity{TGV InOui}, \entity{Air Belgium}, \entity{Brittany Ferries} et \entity{Air Senegal}. L'entreprise \entityb{Moment} a lancé en 2021 une filiale nommée \entity{Moment Care}, qui se spécialise dans le divertissement dans le domaine de la santé: \entity{Moment Care} souhaite révolutionner le contenu des offres de divertissement dans les établissements de santé, et la manière d'y accéder \cite{momentcare}. \subsection{Présentation du lieu de stage} Lors de mon stage, les locaux de \entityb{Moment} se trouvaient à Paris, près de la place de la Bastille. Ces bureaux sont partagés par la grande majorité des employés de \entityb{Moment}, qui sont organisés en différents pôles: \begin{description} \item[Développement full-stack:] C'est au sein de cette équipe que mon stage s'est déroulé, sous la supervision de son chef d'équipe, Pierre Perrin. \item[Marketing \& Design:] Ce pôle s'occupe de l'image de l'entreprise et des produits, à la fois sur les réseaux sociaux et auprès des clients présents et futurs. Cette équipe décide notamment du design des différentes applications, qui est envoyé à l'équipe \entity{Fullstack R\&D} pour implémentation. \item[PMO (Project Management Office):] Ce pôle est constitué de chefs de projets, qui gèrent les demandes des clients, les dates limites, les statistiques à relayer aux clients et les difficultés techniques. \item[Contenu:] L'équipe contenu s'occupe de maintenir la base de contenus disponibles sur les différentes plateformes déployées. Elle négocie auprès des distributeurs de films, de séries et de magazines, et elle maintient à jour le \term{Content Management System} (CMS). \item[Business Developers:] Cette équipe est en contact avec nos clients actuels et de potentiels clients futurs. Elle met en place le business plan, amène à l'entreprise de nouvelles opportunités de partenariat et négocie les prix lors de la vente des produits de l'entreprise. % TODO: reste \end{description} \newpage \subsection{Produits de Moment} \subsubsection{Flymingo} \entity{Flymingo} est le produit principal de \entityb{Moment}: % Pitch de Moment, dire sur quoi c'est déployé Ce produit est composé d'un serveur, nommé \entity{Flymingo Box}, sur lequel tournent plusieures applications: \begin{itemize} \item Une application web, \entity{Flymingo Digital}, sur laquelle les passagers peuvent se connecter. \item La \entity{Content API}, qui est une API pour accéder aux informations sur les différents divertissements disponibles sur le serveur. Cette API permet aux clients d'avoir un certain degré de customabilité. Cette API sert également les différents contenus (vidéo, musique, magazines). % Zirock? \end{itemize} \subsubsection{Mint} % TODO: add logo floating to the right \entity{Mint} est le produit que \entityb{Moment} développe et déploie en ce moment dans les cliniques de santé: \begin{description} \item[Mint Admin] est une application web permettant aux clinique de fixer les prix pour les offres que celles-cis souhaite mettre à disposition, ainsi que de gérer l'assignement des différents appareils (comme les télévisions et les tablettes) aux chambres, des différents patients à ces chambres, et des offres aux patients. \item[Mint Digital] est une application web que les patients des cliniques utilisent pour se connecter, acheter des offres en ligne, regarder des films, documentaires, magazines et écouter de la musique. \item[Mint Service] est le back-end avec lequel \entity{Mint Admin} et \entity{Mint Digital} communiquent. \entity{Mint Service} expose une API permettant à \entity{Mint Admin} de faire des modifications aux offres et aux patients, et à \entity{Mint Digital} de permettre aux utilisateurs de se connecter et d'acheter des offres en ligne. \item[Mint Tab] est une application pour tablettes \term{iPad}, qui permet aux patients des cliniques d'accéder au même contenu que sur \entity{Mint Digital}. \item[Mint TV] est une application tournant sur les télévisions connectées, qui permet aux patients des cliniques d'accéder au même contenu que sur \entity{Mint Digital}. \end{description} Durant ce stage, j'ai surtout travaillé sur les applications suivantes: \begin{itemize} \item Mint Service \item Mint Admin \item Mint Digital \item Mint TV et Mood TV \end{itemize} \section{Organisation du stage} % Durant ce stage, j'ai rejoint l'équipe \entity{Développement Full-Stack - Recherche \& Développement}, % afin de contribuer au développement des applications front-end et back-end de l'entreprise, % à l'assurance de qualité de ces applications et aux choix techniques faits pour ces applications. \subsection{Thèmes définis avant le stage} % Note: commencé avec 9 personnes, puis est passé à 7 personnes % TODO: vérifier sur le portail des stages notre mission Durant mes échanges avec mon tuteur de stage et le directeur des ressources humaines de \entity{Moment}, nous nous étions convenus que j'allais intégrer l'équipe \entity{Développement Full-Stack - Recherche \& Développement} en tant que développeur. Mes tâches au sein de cette équipe seraient de: % https://utbm.jobteaser.com/en/job-offers/8878261-moment-developpeur-se-web-fullstack-stage-ou-alternance % TODO: clarifier qu'est ce qui constitue un projet R&D \begin{itemize} \item Développer de nouvelles fonctionnalités (notamment de nouvelles \term{API} (interfaces de programmation) et de leur intégration côté client) \item Documenter le code (sous forme de commentaires et sous forme de documentation technique) \item Participer aux choix fonctionnels (quelles technologies utiliser, comment organiser des librairies, etc.), et participation à leur implémentation \item Participer à la définition de la roadmap technique, et au suivi de cette roadmap \item Aider à améliorer les solutions déjà existantes (amélioration de performances, de maintenabilité, etc.) \item Participation aux projets Recherche \& Développement \end{itemize} Au moment de mes entretiens pour ma candidature de stage, les thèmes principaux sur lesquels l'équipe travaillaient étaient le développement de \entity{Flymingo Digital} et de \entity{Mood TV}, ainsi qu'un peu de développement pour \entity{Mint}. J'ai aussi pu apprendre que l'équipe utilise la librairie \entity{React} et le framework \entity{Next.JS} pour ses applications front-end, et le moteur javascript \entity{Node.JS} avec le framework \entity{Nest.JS} pour ses applications back-end. J'espérais avant le stage pouvoir surtout travailler sur la partie back-end, car j'avais jusqu'à ce moment-là peu d'expérience avec \entity{React}, et le peu d'expérience que j'avais ne m'inspirait pas confiance en cette technologie. J'ai néanmoins décidé d'apprendre en amont du stage la librairie \entity{Solid.JS} \cite{solidjs}, car je n'avais jusqu'à maintenant que fait du développement front-end \og vanilla \fg (sans librairie ou framework). \entity{Solid.JS} se veut être une librairie de développement front-end plus simple, plus réactive et plus efficace que \entity{React}, et l'apprendre m'a permis d'avoir une première expérience avec la programmation réactive. \subsection{Premiers jours de stage} À mon arrivée au stage, j'ai récupéré l'ordinateur portable qui m'a été préparé avec une installation d'Ubuntu, puis j'ai installé un environnement de développement d'applications dessus (différents outils en ligne de commande, un éditeur de texte et un gestionnaire de fenêtre avec lequel je suis plus à l'aise). J'ai aussi reçu la documentation d'\og onboarding \fg, qui contient une liste de documentations avec lesquelles je devais me familiariser afin de pouvoir travailler efficacement. J'ai parcouru ces documentations et ai testé certaines des fonctionnalités décrites dans celles-cis dans un mini-projet de test. L'équipe se réunit chaque matin pour discuter des nouveautés et du travail de la veille, et pour annoncer sur quoi chaqu'un prévoit de travailler ce jour-ci. J'ai participé à ces réunions dès mon premier jour, ce qui m'a permis de rapidement construire une compréhension des problématiques récurrente et de la dynamique des différentes applications. Nous sommes encouragés dans l'équipe à travailler en \og pair programming \fg, et en général à collaborer ensemble. Ma première contribution au code a été faite en pair programming, après avoir remarqué que la logique pour la complexité des mots de passe dans \entity{Mint Admin} était fausse. Faire cette contribution en pair programming m'a permis d'être guidé dans le processus d'envoi et de vérification de contributions, ainsi que d'être guidé dans l'organisation de la repository. \subsection{Outils utilisés} \newcommand{\logowidth}{0.15\textwidth} \entity{Git} \cite{git} est utilisé pour gérer le versionage du code: cet outil permet de stocker les modifications apportées au code sous forme de \og commits \fg, et de facilement rassembler et gérer les modifications faites par plusieures personnes. % wrapfigure does not work with my \entity :( \begin{wrapfigure}{r}{\logowidth} \centering \includesvg[width=\logowidth]{gitlab_logo.svg} \caption*{GitLab \cite{gitlabsvgs}} \end{wrapfigure} \textbf{GitLab} \cite{gitlab} est utilisé pour stocker les repositories de l'entreprise en ligne, pour stocker en ligne les packages npm \cite{npm} et pour lancer automatiquement les tâches de \term{Continuous Integration}. \textbf{VSCode} \cite{vscode} est un éditeur de texte utilisé par presque toute l'équipe pour modifier ou naviguer le code. \textbf{Slack} \cite{slack} est une plateforme de messagerie instantanée, que l'entreprise préfère aux emails pour la communication indirecte. \textbf{Jira} \cite{jira} est un logiciel de gestion et de suivi de tickets, que notre équipe utilise pour suivre les tâches à faire durant la semaine, quelles tâches sont en cours de développement, prêtes à être revues ou finies, ainsi que pour garder un \term{backlog} des tâches à faible priorité. \textbf{Confluence} \cite{confluence} est un logiciel qui permet à l'équipe de regrouper des documentations qui n'ont pas de place claire au sein du code. \textbf{NX} \cite{nx} est un outil simplifiant la gestion de \og monorepositories \fg (des repositories contenant plusieures applications et librairies). \textbf{NX} est utilisé pour la repository de l'équipe qui contient Mint Service, Mint Admin et Mood TV. L'objectif au long terme et de migrer l'ensemble des projets de l'équipe sur cette repository, car elle permet de facilement réutiliser du code entre les projets et de synchroniser des modifications entre projets. \begin{wrapfigure}{r}{\logowidth} \centering \includesvg[width=\logowidth]{ts-logo-128.svg} \caption*{TypeScript \cite{typescriptlogo}} \end{wrapfigure} \textbf{Typescript} \cite{typescript} est une extension au langage JavaScript, qui ajoute un système de vérification de types. Typescript permet d'éviter une classe de bugs causés par des valeurs passées à des fonctions attendant un certain type en entrée. \\ Typescript existe aujourd'hui en tant que langage qui doit être transpilé en javascript avant de pouvoir être utilisé dans Node.JS ou dans un navigateur, mais certains interpréteurs (comme \textbf{Bun} \cite{bun}) supportent le typescript, et il existe une initiative pour standardiser un système permettant d'ajouter des types en javascript sans devoir le traduire. \textbf{React} \cite{react} est une librairie JavaScript qui permet de facilement construire des interfaces graphiques fortement intéractives. React permet d'encapsuler l'affichage et la gestion d'évenéments dans des \og composants \fg, qui peuvent être réutilisés de manière modulaire. React propose aussi une extension de JavaScript, qui permet d'écrire du code HTML directement dans le code JavaScript, ainsi que d'insérer des composants avec la même syntaxe. \textbf{Next.JS} \cite{nextjs} est un framework simplifiant l'utilisation de React pour des plus grandes applications: NextJS permet de séparer l'application en différentes pages, et de naviguer de manière inintérompue entre ces pages. NextJS a également pour but d'optimiser la vitesse de chargement de ces pages, en faisant un maximum du rendu de ces pages côté serveur. \textbf{Nest.JS} \cite{nestjs} est un framework simplifiant la création d'applications back-end. NestJS utilise l'injection de dépendance pour permettre de plus facilement faire grandir une application back-end, et propose de nombreux outils pour gérer les requêtes, les bases de données et la documentation. \subsection{Organisation de l'équipe} % Agile, poker planning % Backlog, recettes, versioning \subsection{Planning} % Afin de pouvoir développer \entity{Mint TV} sans duplication de code, % nous avons décidé de prendre l'ensemble des composants de \entity{Mood TV}, % de les nettoyer et des les mettre dans une librairie au sein de la monorepository. \section{Travail réalisé sur Mint Service} Mint Service est une application construite avec \entity{NestJS}. NestJS est un framework permettant de construire des applications côté serveur en JavaScript, et de s'assurer que ces applications soient à la fois sûres, efficaces et flexibles \cite{nestjs}. \subsection{NestJS et organisation du code} % TODO: hiérarchiser l'argumentaire NestJS emploie à son coeur les principes de \term{modularité} et d'\term{inversion de contrôle} (\term{IoC}): \\ L'application est séparée en différents modules, qui eux-mêmes contiennent des \term{services} et des \term{controleurs}. \figref{nestjs3} \begin{description} \item[Les services] (aussi appelés \term{providers}) contiennent l'implémentation de la logique nécessaire pour répondre aux besoins de l'application: contacter une base de donnée, traiter l'information, faire des requêtes réseau, etc. \item[Les controleurs] sont responsables d'accepter les requêtes des \entity{clients}, de les transformer, de vérifier leur légitimité et d'appeler les méthodes des \entity{services} avant de transformer la réponse à envoyer au \entity{client}. \\ NestJS fournit un ensemble d'outils simplifiant l'implémentation des controleurs. \item[Les modules] s'occupent de gérer la configuration des \entity{services} et des \entity{controleurs}: chaque \entity{module} indique à NestJS quels \entity{services} et \entity{controleurs} il contient, ainsi que comment NestJS doit construire ces services dans les cas plus complexes. \\ Les modules peuvent exporter un sous-ensemble de leurs services, ce qui permet de rapidement réutiliser des services en important le module leur étant associé. \figref{nestjs2} \end{description} \begin{figure}[H] \centering \includegraphics{nestjs3} \caption{Organisation d'un module NestJS typique} \label{nestjs3} \end{figure} La séparation entre controleurs et services permet d'avoir une claire \term{séparation des préoccupations}: \begin{itemize} \item Les controleurs s'occupent de gérer, valider et répondre aux requêtes faites par un client; \item Les services s'occupent de l'implémentation de la logique permettant de satisfaire la requête; \item Les modules s'occupent de configurer les services et les controleurs, et permettent la modularisation du code. \end{itemize} Pour limiter le couplage entre les services, et pour simplifier la réutilisation des services, NestJS permet de faire de l'\term{injection de dépendances} par \term{constructeur sans défaut} \cite{yang2008empirical} dans les services et dans les controleurs, d'une manière similaire au framework \entity{Spring} en \entity{Java}. \figref{nestjs1} % TODO: trouver une source % Separation of concerns % https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=0fd24fa8ac2a77c4709103eb8a179fec38311fe8 % "On the importance of the separation-of-concerns principle in secure software engineering" Il devient ainsi plus simple avec ce système de modifier différentes parties du code sans accidentellement casser une autre partie du code. Il est aussi plus simple de tester du code organisé de la manière suivante, car les services et les controleurs peuvent être placés dans un environnement isolé et testés individuellement ou collectivement. \subsection{Système d'envoi de mail} \subsubsection{Analyse et prototype} On m'a donné en début de stage la tâche d'implémenter un système d'envoi de mail pour \entity{Mint Service}. Ce système prend la forme de plusieurs librairies, qui doit remplir les conditions suivantes: \begin{itemize} \item Il doit être facilement réutilisable dans d'autres projets. \item Il doit permettre de changer de fournisseur de service pour l'envoi d'emails sans devoir faire de grands changements du côté des utilisateurs de la librairie. \item Il doit pouvoir envoyer des emails qui s'affichent de la manière voulue sur la majorités des boîtes mail. \item Il doit pouvoir envoyer des emails contenant des informations sur l'utilisateur; cette étape devra être faite avec le service de \term{templates} d'email sur \entity{Amazon SES} \cite{amazonses} \cite{amazonsestemplate} \item Il doit permettre de décrire le contenu des emails d'une manière facilement maintenable et réutilisable. \end{itemize} Mon travail a commencé par l'analyse de différentes solutions permettant d'adresser les deux dernières conditions. Par le passé, l'entreprise avait déjà utilisé le moteur \entity{Handlebars} \cite{handlebars}, une librairie de recherche et de remplacement de texte, qui permet d'avoir des formes simples de logique, comme des conditions ou des boucles. Bien que \entity{Handlebars} fonctionne bien pour insérer les informations de l'utilisateur dans les mails, il ne permet pas de facilement réutiliser du code, qui est souvent complexe afin d'assurer un bon affiche sur les différents programmes de boîte mail. J'ai donc cherché à avoir un système de \og composants \fg dans la solution choisie, afin de pouvoir construire des couches d'abstraction et de réutiliser facilement le code. Ces composants doivent, plus spécifiquement: \begin{itemize} \item Pouvoir être appelés avec différentes valeurs en arguments \item Pouvoir appeler d'autres composants \end{itemize} % TODO: source sur search and replace J'ai selectionné deux moteurs de recherche et de remplacement de texte (\term{Search and Replace}): \entity{Handlebars} \cite{handlebars} et \entity{Mustache} \cite{mustache}. Ces deux moteurs opèrent de manière similaire: ils lisent le code source, et lorsqu'une variable indiquée par les balises \texttt{\{\{} et \texttt{\}\}} est rencontrée, celle-ci est subtituée par la valeur assignée au nom de cette variable. \entity{Handlebars} et \entity{Mustache} peuvent tous les deux être utilisés pour implémenter le système de composants voulu, car ils permettent de définir des variables spéciales, que les deux moteurs appelent \term{partials}, qui peuvent appeler du code javascript arbitraire. J'ai enfin fait un prototype en \entity{Typescript}, qui transforme un email décrit à partir de composants \entity{Handlebars} ou \entity{Mustache} en du HTML. Après avoir montré ce prototype à mon chef de projet, nous étions tous les deux d'accord que le moteur \entity{Handlebars} remplissait mieux nos attentes, en grande partie parce que \entity{Handlebars} permet de passer du code en tant qu'\og enfants \fg, tandis que \entity{Mustache} requiet de passer par deux composants (un avant et un après le code \og enfant \fg). \figref{hbs1} \inputfig{hbs1} Pour le premier projet sur lequel \entity{Mint Service} allait être déployé, \entity{Amazon SES} \cite{amazonses} allait être utilisé pour faire l'envoi de mails. \entity{Amazon SES} permet d'envoyer les emails sous format texte et HTML en même temps, permettant d'avoir des emails facilement lisibles par un lecteur d'écran ou sur une messagerie configurée pour afficher les mails sans leur mise en forme. La partie \entity{Handlebars} a donc été étendue pour permettre d'annoter quels parties du code doivent être placés dans la version texte du mail. [Figures~\ref{hbs2a} et \ref{hbs2b}] \inputfig{hbs2} \subsubsection{Implémentation initiale dans Mint-Service} Une fois que le prototype me donnait des résultats satisfaisants, j'ai pu passer à l'implémentation au propre du système d'envoi de mails dans \entity{Mint Service}. Cette première implémentation devait faire l'envoi de mail en deux étapes: \begin{enumerate} \item Les mails sont chargés et sont rendus, puis sont mises en lignes sur \entity{Amazon SES} en tant que \og templates \fg \cite{amazonsestemplate} \item Les mails sont ensuite envoyés en instructant à \entity{Amazon SES} de faire le rendu et l'envoi d'une des \term{templates} à l'adresse mail voulue, avec les données voulues \end{enumerate} J'ai d'abords créé et implémenté une librairie permettant de compiler du code \entity{Handlebars} ainsi que des composants en format HTML et en format texte, nommée \texttt{handlebars-generator}. Cette librairie ne s'occupe pas du chargement des fichiers, ni de l'envoi des mails, et est implémentée sans framework, ce qui permet de la réutiliser dans le futur pour d'autres projets. Puis, j'ai créé et implémenté une librairie Nest.JS nommée \texttt{mailing-nest} qui s'occupe de: \begin{itemize} \item Charger les composants et les emails depuis un dossier donné \item Transformer ceux-cis avec \texttt{handlebars-generator} en HTML et en texte \item Mettre en ligne des \term{templates} pour utiliser le service d'envoi d'emails personalisés d'\entity{Amazon} \item Envoyer les \term{templates} avec les informations de l'utilisateur dedans avec \entity{Amazon SES} \end{itemize} Afin de pouvoir tester le fonctionnement de la librairie \texttt{mailing-nest}, j'ai également créé une petite application Nest.JS qui affiche dans le navigateur les emails en format HTML et en format texte. Cette application permet aussi de développer rapidement les emails sans devoir passer par Amazon pour tester les modifications. % TODO: screenshots Enfin, j'ai implémenté un module Nest.JS dans l'application \entity{Mint Service}, qui charge le module de \texttt{mailing-nest} avec en paramètre le chemin des emails pour \entity{Mint}. Ce module est importé à plusieurs endroits dans le code, et expose des méthodes dans son service permettant de convertir les entités de \entity{Mint Service} au format attendu par les emails. \begin{figure}[H] \includegraphics[width=\textwidth]{mailingnest} \caption{Organisation initiale du système d'envoi de mail dans Mint-Service} \end{figure} Avec le système de mail en place, j'ai pu implémenter la première template d'email, qui était celle pour l'envoi d'identifiants au patients. Très rapidement, j'ai pu voir sur \url{caniemail.com} que la quasi-totalités des fonctionnalités HTML5 modernes n'étaient pas supportés par \entity{Microsoft Outlook}, ce qui nous forcerait à utiliser des \texttt{} dans l'entièreté des emails pour pouvoir supporter \entity{Microsoft Outlook}, qui est à ce jour le 3ème client email le plus utilisé du monde \cite{oberloemailclients}. Une solution à ce problème est d'utiliser une librairie assurant la compatibilité avec \entity{Outlook}. J'ai choisi la librairie \entity{MJML} \cite{mjml}, qui utilise un langage ressemblant au html, qui est ensuite compilé en HTML compatible avec \entity{Outlook}: \inputfig{email} \subsection{Rétrospective sur le système d'envoi de mails} % - [x] parler des désavantages de cette méthode % - [x] parler de ce qu'on prévoyait de faire % - [~] parler de comment on l'a fait (pour showcase l'avantage du monorepo), et des étapes prises % - [x] parler des améliorations futures qui pourront être faites % (ajouter plus de providers, simplifier la logique pour choisir les providers, react.email, svelte, etc.) % - [ ] Comparer la maintenabilité Après avoir fini l'implémentation du système de mail, j'ai pu l'observer alors qu'il est passé par la vérification de qualité, des déploiements et recettes sur un serveur local, et enfin des déploiements chez les clients. Les deux librairies ont vu peu de changements, et ont fonctionné comme voulu. L'organisation du code au sein de \entity{Mint Service} a pris deux essais pour arriver à un format satisfaisant: le premier essai plaçait l'envoi des mails dans un service dédié à la gestion des utilisateurs (\texttt{GuestModule}), mais il s'averrait qu'il fallait assez de code pour préparer les informations des mails qu'il était préférable de déplacer la logique d'envoi des mails dans un module à part, \texttt{MintMailingModule}. Malgré \entity{MJML} et le système de composants, écrire des templates d'emails reste plus compliqué à écrire que du code React: \begin{itemize} \item La différence de format entre les templates Handlebars/MJML et les composants React fait qu'il est difficile d'appliquer les intuitions valables pour le React lorsqu'on écrit ou réécrit des templates d'emails. \\ Ceci est en grande partie dû au fonctionnement de MJML, qui requiet une structure stricte dans le code (\texttt{mj-body} $\rightarrow$ \texttt{mj-section} $\rightarrow$ \texttt{mj-column} $\rightarrow$ texte). \\ HTML lui a une structure plus flexible, permettant d'imbriquer la pluspart des éléments disponibles dans un ordre arbitraire. \cite{mdncontentcategories} \item Le choix de faire le rendu final des templates via les templates d'\entity{Amazon SES} rend l'écriture des emails plus compliquée (il faut mixer ensemble deux différents formats handlebars, l'un étant interprété de notre côté, et l'autre étant interprété du côté d'\entityb{Amazon SES} \figref{emailsrchbs}). \\ Ce choix rend aussi le débogage de toute erreur lors du deuxième rendu très compliqué, car le seul moyen pour accéder aux erreurs d'envoi de mails sur \entityb{Amason SES} est de mettre en place un système de transfert de messages, puis de l'activer en envoyant les mails avec un paramètre précis. \end{itemize} Pour palier à la deuxième difficulté, j'ai décidé vers la fin de mon stage de modifier l'implémentation du système d'envoi de mails, afin de faire l'entièreté du rendu de notre côté, et d'uniquement utiliser \entity{Amazon SES} pour l'envoi pur des mails. J'avais également comme but secondaire de rendre ce système plus robuste, en permettant notamment l'insertion de code pour vérifier la validité des données insérées dans les emails lorsqu'on est dans un environnement de développement. Les modifications ont été faites dans l'ordre suivant, qui permettait de progressivement appliquer les changements nécessaires: \begin{enumerate} \item Suppression de la transformation des balises secondaires (\texttt{[[} et \texttt{]]}) et des options associées \item Marquage de différents types comme dépréciés, et ajout de types pour l'envoi pur d'emails \item Dépréciation des méthodes d'envoi d'email via les templates SES (\texttt{sendTemplatedEmail}), et ajout des méthodes pour l'envoi pur d'emails (\texttt{sendEmail}) \item Modification des templates pour ne plus utiliser les balises secondaires \item Modification de l'application de prévisionage des emails pour utiliser le nouveau format des informations substituées dans les mails \item Modification de \entity{Mint Service} pour utiliser \texttt{sendEmail} au lieu de \texttt{sendTemplatedEmail} \item Suppression de \texttt{UploadModule} et de \texttt{sendTemplatedEmail} \item Suppression des types inutilisés \end{enumerate} À la suite de ces modifications, les emails s'affichent de la même manière qu'avant, et le système d'envoi de mails est désormais plus simple à utiliser et plus simple à étendre avec différents services d'envoi de mail. Je n'ai pas pu implémenter le système de validation des données, par soucis de difficulté d'implémentation: il aurait fallu étendre le système de chargement de composants pour également charger du code Javascript, et transformer le format des données utilisé par Handlebars en un format facilement vérifiable. \\ Il est par contre maintenant possible d'écrire dans \entityb{Mint Service} des tests pour s'assurer que la logique de transformation des données reste compatible avec les emails. À la suite de cette modification, je pense qu'il est encore possible d'améliorer de différentes manières ce système d'envoi de mails: \begin{itemize} \item En ajoutant plus de tests automatisés dans le système, notamment des tests d'intégration \item En rendant les différents modules plus simples d'utilisation \item En permettant d'utiliser une syntaxe plus proche de celle de React pour appeler des composants (\texttt{} au lieu de \texttt{\{\{>Composant\}\}}) \item En utilisant un système comme \href{https://react.email/}{React Email} ou \href{https://astro.build/}{Astro} pour écrire les templates en Javascript, ce qui permetterait aussi de faire de la vérification des données et des types. \end{itemize} \begin{figure}[H] \includegraphics[width=\textwidth]{mailingnest-2} \caption{Organisation finale du système d'envoi de mail dans Mint-Service} \end{figure} \section{Travail sur Mood TV} \subsection{Introduction?} \entity{Mood TV} est une application tournant sur les télévisions \og intelligentes \fg produites par \entity{LG}. Ces télévisions font tourner le système d'exploitation \entity{WebOS}, et la version pour laquelle nous visons l'application utilise \entity{Chrome 53}. Comme ces télévisions utilisent chrome, notre application peut être programmée entièrement en React, à condition de s'assurer que le code javascript soit compatible avec cette version de chrome. Mon travail sur \entity{Mood TV} a été d'optimiser le temps de chargement de la page: avant, celle-ci prenait environ 10 secondes à charger, et j'ai été laissé en autonomie pour trouver pourquoi le temps de chargement est si haut et comment le baisser. % Présentation de la plateforme, des télés (chrome 53 hehe), mentionner procentric % Parler de l'hydration, du rendu, etc. \subsection{Analyse des performances} La première étape avant de pouvoir optimiser les performances de l'application est de mesurer ses performances. Il faut pour celà mesurer de manière précise le temps moyen de chargement, et il faut pouvoir avoir un aperçu de quelles opérations prennent le plus de temps. J'ai tout d'abords activé le mode de débogage sur la télévision, qui peut être fait via l'API propriétaire de contrôle de la télévision. Avec ce mode de débogage, on peut se connecter depuis une interface web aux outils de développeur du navigateur tournant sur la télévision. J'ai ensuite pu prendre plusieurs profils de performance pour observer quelles opérations prenait le plus de temps: \begin{figure}[H] \includegraphics[width=\textwidth]{mood-tv-before.png} \caption{Profil du chargement de la page, avant toute optimisation; annoté} \label{moodtvbefore} \end{figure} On peut séparer le temps de chargement en différentes étapes: \begin{enumerate} \item Le chargement initial (en bleu), qui est le moment durant lequel le navigateur télécharge le code javascript, et durant lequel \entity{webpack} prépare ce code pour reproduire un environnement modulaire moderne. \item L'hydration \cite{hydration}, qui est une étape du rendu avec React: cette étape du chargement permet à React d'attacher son arborescence d'état au HTML existant, permettant d'intéragir dans le code React avec les éléments du DOM. \item La réception des \og catégories \fg, qui consiste au traitement de deux requêtes faites à l'API sur laquelle se trouve le \term{Content Management System} \item L'envoi de requêtes pour récupérer les informations des films présents dans ces catégories \\ On peut déjà observer sur cette capture d'écran que cet envoi est en triple, alors qu'il ne devrait n'y avoir qu'une vague. \item La réception des informations de films, et le traitement du résultat de ces requêtes. \end{enumerate} Ensuite, il me fallait un moyen de mesurer de manière précise les performances avant de pouvoir faire des changements. La solution que j'ai trouvé a été de créer et d'implémenter un protocole d'envoi et de réception de performances: \figref{moodtvperf} \begin{itemize} \item La télévision mesure les performances avec l'API javascript \texttt{Performance} \cite{performanceapi}, puis envoie ces valeurs via une requête sur un petit serveur sur mon ordinateur. \item Ce serveur stoque ensuite toutes les valeurs reçues dans un fichier, et peut relire de ce fichier si jamais il faut reprendre la mesure de performance. \item Un programme lit les valeurs du fichier, puis calcule la moyenne, l'écart standard de ces valeurs. Ce programme peut aussi lire deux fichiers, et comparer les performances entre ceux-cis. \end{itemize} \begin{figure}[H] \includegraphics[width=\textwidth]{moodtvperf} \caption{Protocole d'envoi et de réception de performances} \label{moodtvperf} \end{figure} Les valeurs obtenues sont sous la forme de listes de nombres, une liste par métrique mesurée. Soit $(\omega_1, \omega_2, ..., \omega_n)$ une telle liste. Si on suppose que ces valeurs correspondent à différents résultats d'une même expérience $X$, alors on peut calculer la moyenne empirique ($\mu^{\star}_n$) et la variance ($(\sigma^{\star}_n)^2$) empirique de ces valeurs de la manière suivante: \begin{align*} \mu^{\star}_n &= \frac{\sum_{i=1}^{n} \omega_i}{n} \\ (\sigma^{\star}_n)^2 = S_{n-1} &= \frac{\sum_{i=1}^{n} (\omega_i - \mu^{\star}_n)^2}{n-1} \\ &= \frac{(\mu^{\star}_n)^2}{n-1} - \frac{\sum_{i=1}^{n} \omega_i^2}{n(n-1)} \\ \\ \mu^{\star}_n \xrightarrow{n\rightarrow\infty} \mu & \quad \quad \quad \sigma^{\star}_n \xrightarrow{n\rightarrow\infty} \sigma % TODO: preuve? \end{align*} Afin de pouvoir comparer différents ensembles de valeurs, je fais l'hypothèse que les valeurs suivent une loi normale ($X \hookrightarrow \mathcal{N}(\mu, \sigma^2)$). % TODO: refine Dans ce cas, on peut utiliser une approximation de la distribution de student pour calculer un intervale de confiance pour $\mu$. J'utilise comme taux de confiance $\alpha = 0.95$: \begin{align*} \mu &\in [\mu^{\star}_n - z_{1-\alpha/2} \frac{\sigma^{\star}_n}{\sqrt{n}}, \mu^{\star}_n + z_{1-\alpha/2} \frac{\sigma^{\star}_n}{\sqrt{n}}] \\ z_a \;&\text{est tel que} \int_{-\infty}^{z_a}{\frac{e^{-\frac{(x-\mu)^2}{2\sigma^2}}}{\sigma\sqrt{2\pi}}}=a \end{align*} Enfin, on peut utiliser le t-test pour estimer si deux valeurs différentes $X$ et $Y$ diffèrent bien de moyenne. \cite{ttest} Pour \entity{Mood TV}, les valeurs mesurées sont les suivantes, en millisecondes: \begin{itemize} \item Le temps jusqu'au début de l'hydration: \textbf{hydration} \item Le temps jusqu'à la première éxecution des \texttt{useEffect}: \textbf{mount} \item Le temps jusqu'à ce que l'entièreté des requêtes pour charger les informations des films soient finies: \textbf{ready} \end{itemize} \inputfig{perf1} % Screenshot du panel des performances sur mood tv (avant et après) % Parler de la loi du milieu, du Z-test, du test de normalité, de comment récupérer ces données \subsection{Optimisation du temps de chargement} % - [x] Optimisation du nombre de requêtes faites (avec un dessin? ~ plus tard) % - [x] Optimisation de la taille du bundle % - [x] Optimisation du parsing des requêtes % - [x] Avoir de jolis nombres % - [ ] tableau final avec toutes les mesures \subsubsection{Optimisation du nombre de requêtes} La première optimisation a été d'éviter que les requêtes pour récupérer les informations sur les films ne soient envoyées plusieures fois. La fonction pour faire la requête pour une catégorie (\texttt{getItems}) utilisait un \texttt{useCallback} et un cache gêré par React, ce qui faisait que dès que les informations d'un film était récupéré et stocké dans le cache, React assignait une nouvelle référence à \texttt{getItems}, causant le \texttt{useEffect} responsable pour charger l'ensemble des informations des films à s'éxecuter à nouveau, et de nouvelles requêtes sont envoyées en conséquence. \figref{fromeffectloop} Pour résoudre ce problème, j'ai créé une nouvelle fonction qui récupère l'entièreté des informations des films, et qui seulement une fois que toutes les requêtes soient finies stoque ces informations dans le cache. \inputfig{perf2} \subsubsection{Optimisation de la taille du bundle} Ensuite, j'ai optimisé la taille du bundle javascript, pour passer de $350$ kilooctets à $243$ kilooctets, en enlèvant les librairies qu'on n'utilisait peu et qui prenaient beaucoup de place, comme \texttt{browserify-crypto}. Réduire la taille du bundle permet de réduire le temps passé à télécharger le code javascript de la page, et le temps passé à compiler ce code et à charger les différents modules avec \entity{webpack}. \inputfig{perf3} \subsubsection{Optimisation du traitement des réponses} Enfin, j'ai optimisé la logique de traitement des réponses des requêtes pour récupérer les informations sur les films. Ce traitement, jusqu'à ce moment, se faisait grâce à la librairie \texttt{class-transformer} \cite{classtransformer}, qui permet de facilement transformer des objets ordinaires en instances de classe. Cette librairie est utilisée pour transformer les résultats des requêtes, qui sont sous forme d'objets ordinaires, en instances de classes proposant des fonctions pour facilement traiter les informations contenues dedans. Malheureusement, \texttt{class-transformer} ajoute beaucoup de temps de calcul, qui sur le hardware de la télévision connectée, se traduit en secondes de chargement en plus. \cite{classtransformerbenchmark} J'ai donc remplacé \texttt{class-transformer} par une transformation manuelle pour les listes de films, qui copie manuellement les données des films et des catégories en instances de classe. Avant de faire ce changement, j'ai d'abords écrit des tests unitaires pour vérifier le comportement du système déjà en place. Puis, j'ai progressivement modifié les fonctions de traitement de requête affectées pour utiliser ma transformation manuelle à la place. % Les seuls tests présents auparavant étaient des tests d'intégration, qui avaient cassé au fil des mois et qui ne fonctionnent plus ajourd'hui. % J'ai donc dû nettoyer les tests d'intégration existants pour les faire tourner séparemment des tests unitaires. \inputfig{perf4} \subsection{Résultats et rétrospective} Avec ces optimisations, la page prend désormais entre 4 et 6 secondes pour charger, contre 10 à 15 secondes auparavant. Le temps d'éxecution sur le processeur de la télévision n'est aussi plus un engorgement, et on peut voir sur le profil des performances qu'une bonne partie du temps est passé à attendre que les différentes requêtes se finissent. \figref{moodtvafter} \begin{figure} \includegraphics[width=\textwidth]{mood-tv-after.png} \caption{Profil du chargement de la page, après les optimisations; annoté} \label{moodtvafter} \end{figure} Faire ce travail m'a permis d'avoir une compréhension plus profonde sur différents sujets: \begin{itemize} \item Les techniques d'optimisation logicielle (profilage, benchmarking) \item Le modèle de propagation de mises à jour de React (\texttt{useEffect}, les boucles d'évenements infinies \figref{fromeffectloop}) \item L'optimisation de la taille des bundle javascript \item L'extraction de données de performances depuis le navigateur (web vitals \cite{webvitals}, \texttt{reportWebVitals} sur Next.JS \cite{nextjsvitals}) \item L'analyse de données de performances (z-test, t-test, intervale de confiance) \end{itemize} \makeutbmbackcover{} \newpage \begingroup \raggedright \bibliographystyle{plain} \bibliography{references}{} \endgroup \newpage \section{Annexes} \subsection{Listings de code} \inputfig{nestjs1} \inputfig{nestjs2} \inputfig{email-src-hbs} \inputfig{email-src-mjml} % \inputfig{ttest} \inputfig{fromeffectloop} \end{document}