z_a \;&\text{est tel que}\int_{-\infty}^{z_a}{\frac{e^{-\frac{(x-\mu)^2}{2\sigma^2}}}{\sigma\sqrt{2\pi}}}=a
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*}
\end{align*}
Enfin, on peut utiliser le t-test pour estimer si deux valeurs différentes $X$ et $Y$ diffèrent bien de moyenne. \figref{ttest}
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}
\inputfig{perf1}
@ -789,49 +764,100 @@ Enfin, on peut utiliser le t-test pour estimer si deux valeurs différentes $X$
\subsection{Optimisation du temps de chargement}
\subsection{Optimisation du temps de chargement}
% - [x] Optimisation du nombre de requêtes faites (avec un dessin? ~ plus tard)
% - [x] Optimisation du nombre de requêtes faites (avec un dessin? ~ plus tard)
% - [ ] Optimisation de la taille du bundle
% - [x] Optimisation de la taille du bundle
% - [ ] Optimisation du parsing des requêtes
% - [x] Optimisation du parsing des requêtes
% Avoir de jolis nombres, et un tableau final avec toutes les mesures
% - [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 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 un seul film (\texttt{getItem}) utilisait un \texttt{useCallback} et un cache gêré par React,
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é, React assignait une nouvelle référence à \texttt{getItem},
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 à tourner à nouveau,
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.
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,
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.
et qui seulement une fois que toutes les requêtes soient finies stoque ces informations dans le cache.
\inputfig{perf2}
\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,
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}.
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,
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 à laisser webpack charger.
et le temps passé à compiler ce code et à charger les différents modules avec \entity{webpack}.
\inputfig{perf3}
\inputfig{perf3}
Enfin, j'ai optimisé la logique de traitement des réponses
\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.
\subsection{Refactors}
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}
\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}
% - keyboard handler
% - customisations (si ça passe à temps)
% - remise en place de l'ISR, avec un vrai système pour l'activer et le désactiver