forked from HEIG-VD/template-tb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
beescreens.tex
282 lines (212 loc) · 18.2 KB
/
beescreens.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
\section{Environnement existant}
Le code de tous les projets existants réalisés par l'équipe \gls{beescreens} se trouve dans un unique dépôt \gls{gitlab}~\cite{beescreens}. En effet, le dépôt est organisé sous la forme d'un monorepo. Ce qui signifie que tous les projets sont regroupés au lieu d'avoir un dépôt par projet comme il était surtout courant auparavant. Cette pratique a émergé au début des années 2000, notamment grâce aux grands noms de la tech comme Google, Meta ou encore Airbnb. Cela facilite entre autre la collaboration entre les développeurs qui ont directement accès au code complet.
Le dépôt est géré grâce à une workspace \gls{pnpm}~\cite{pnpmworkspace} afin de gérer le fait qu'il s'agisse d'un monorepo. Un fichier de configuration est créé à la racine du répertoire en spécifiant la liste et le chemin vers tous les projets contenus dans le répertoire. Cela permet notamment d'installer les dépendances de tous les projets en une seule commande.
\gls{pnpm} est une version améliorée du gestionnaire de paquets par défaut présent avec \gls{nodejs}~\cite{nodejs} \gls{npm}. Il permet notamment de gérer les dépendances de manière plus efficace en utilisant des liens symboliques afin de ne pas avoir à copier les dépendances dans le dossier \texttt{node\_modules} de chaque projet. Cela donne la possibilité de gagner en temps de compilation et en espace disque. De plus, comme évoqué précédemment, \gls{pnpm} offre une gestion des monorepos plus efficace grâce à la notion de workspace.
\subsection{Structure du répertoire}
\begin{listing}[H]
\begin{tcolorbox}[arc=0mm,colback=white!5!white]
\dirtree{%
.1 /.
.2 apps.
.3 media-player.
.3 pimp-my-wall.
.2 deployment.
.3 media-player.
.3 pimp-my-wall.
.3 ....
.2 docs.
.2 packages.
.3 pimp-my-wall.
}
\end{tcolorbox}
\caption{Structure du répertoire du projet BeeScreens}
\label{listing:beescreeens-repo-structure}
\end{listing}
Le dossier \texttt{apps} contient les applications déjà développées qui sont pour l'instant:
\begin{enumerate}
\item Media Player : une application permettant de lire des images ainsi que des vidéos afin d'afficher entre autre les sponsors et diverses informations lors du festival sous forme de diaporama.
\item Pimp My Wall : l'application majeure du projet permettant aux utilisateurs de collaborer en temps réel en dessinant sur la même toile virtuelle. Pimp My Wall pourra servir de point de repère lors du développement de \gls{beeplace} comme elles ont des fonctionnalités similaires (ex: temps réel, canvas partagé entre les utilisateurs, etc.).
\end{enumerate}
Le dossier \texttt{deployment} contient les fichiers nécessaires au déploiement des diverses applications à l'aide de \gls{docker}~\cite{docker} ainsi que de \gls{docker-compose}~\cite{docker-compose}. Chaque application possède son propre dossier contenant le fichier \texttt{docker-compose.yml} configurant les différents services ainsi que les fichiers de configuration des variables d'environnement utilisées en production.
Le dossier \texttt{docs} contient le code source de la documentation en ligne du projet~\cite{beescreensdocs}. Celle-ci contient notamment divers tutoriels afin de créer de zéro des versions simplifiées des applications développées par l'équipe \gls{beescreens}. De plus, divers guides ont également été créés afin de faciliter la prise en main des technologies utilisées dans le répertoire.
Pour finir, dossier \texttt{packages} contient les différents paquets \gls{npm} utilisés pour partager du code entre différentes applications (ex: entre la partie client et serveur d'une application).
\subsection{CI/CD}
L'intégration continue est présente à deux niveaux: en local sur l'ordinateur du développeur avec Husky~\cite{husky} et en ligne, sur \gls{gitlab} avec les différentes pipelines.
\subsubsection{Husky}
Husky permet d'exécuter certaines tâches automatiquement avant de valider l'envoi du code sur le dépôt \gls{gitlab}. Avant chaque "push", ces différentes étapes sont testées pour chaque application dont le code a été modifié:
\begin{itemize}
\item \textbf{spellcheck}: vérifie l'orthographe du code et des commentaires avec l'outil CSpell~\cite{cspell}.
\item \textbf{review}: valide que le code est bien formaté et que l'analyse de code statique avec des outils comme ESLint~\cite{eslint} est correcte.
\item \textbf{build}: valide que le code compile sans erreur.
\item \textbf{test}: valide que les tests unitaires et d'intégration passent sans erreur.
\end{itemize}
Lancer toutes ces vérifications en local avant de passer sur la pipeline \gls{gitlab} permet de gagner du temps et de ne pas avoir à attendre que la pipeline se termine pour se rendre compte qu'il y a une erreur dans le code.
\subsubsection{Pipeline \gls{gitlab}}
La pipeline est organisée en diverses étapes, appelées "stages". Celles-ci ressemblent aux étapes Husky présentée ci-dessus. Il y a cependant deux étapes supplémentaires:
\begin{itemize}
\item \textbf{init}: configure l'environnement de la pipeline avant toutes les autres étapes;
\item \textbf{deliver}: permet de créer l'image \gls{docker} de l'application et de la publier dans le répertoire \gls{gitlab}.
\end{itemize}
Cette dernière étape sera abordée plus en profondeur dans la prochaine section \ref{sec:deploiement} concernant le déploiement.
Chaque application a son propre fichier de pipeline qui est exécuté uniquement si le code de l'application est modifié. Ces fichiers définissent plusieurs actions appartenant chacune à une des étapes évoquées précédemment. Chaque action se base sur un fichier de "template", afin de limiter le doublon de code entre les différentes applications.
Ces étapes sont exécutées à chaque nouveau commit sur une branche. De plus, lorsque la branche est terminée et que le code est fusionné avec la branche principale, la pipeline est exécutée une dernière fois pour toutes les applications du dépôt, afin de vérifier que rien n'a été cassé par la fusion.
\subsection{Déploiement}
\label{sec:deploiement}
Aucun service tiers n'est utilisé pour le déploiement des applications. En effet, le déploiement se fait directement sur une machine virtuelle fournie par la HEIG-VD, à l'aide de \gls{docker} et \gls{docker-compose}. Chaque application possède son propre fichier \texttt{docker-compose.yml} dans le dossier \texttt{deployment}.
\subsubsection{Docker}
Chaque application dispose d'un fichier \texttt{Dockerfile} permettant de créer l'image \gls{docker} de l'application à sa racine. Afin de rendre la création de l'image plus rapide et plus légère, le \texttt{Dockerfile} ne build pas l'application et n'a donc pas besoin d'installer les dépendances. La pipeline build l'application, puis le dossier \texttt{.bundle} contenant le code source compilé est copié dans l'image \gls{docker} comme le montre le listing \ref{listing:dockerfile-beeplace-frontend}. Finalement, l'application est démarrée avec la commande \texttt{npm start} grâce au fait que \gls{docker} utilise une image de base contenant \gls{nodejs}.
\begin{listing}[H]
\begin{minted}[linenos]{sh}
# Base image
FROM node:20-alpine
# Work directory
WORKDIR /app
# Copy the files of the working directory
COPY .bundle .
# Exposed ports
EXPOSE 4000
# Command to run on start
CMD ["npm", "start"]
\end{minted}
\caption{Dockerfile d'exemple d'une application \gls{javascript} \gls{beescreens}}
\label{listing:dockerfile-beeplace-frontend}
\end{listing}
Une fois l'image \gls{docker} créée, elle est publiée lors de l'étape \textbf{deliver} de la pipeline \gls{gitlab} sur le "Container Registry"~\cite{beescreens-container-registry} du dépôt BeeScreens. Cela permet de mettre à disposition publiquement l'image pour qu'elle soit utilisée par la suite dans le fichier \texttt{docker-compose.yml}. Chaque image est publiée avec le tag \texttt{latest} si aucun nom de commit n'est spécifié.
\subsubsection{Docker-compose}
Le fichier \texttt{docker-compose.yml} de chaque application est très similaire. Il définit les différents services de l'application, comme son frontend, son backend et ses éventuelles bases de données. Des fichiers d'environnements sont importés afin de pouvoir configurer facilement les services. La ligne 11 du listing \ref{listing:docker-compose-example-app} montre que l'image \gls{docker} est bien importée du "Container Registry" évoqué précédemment. Dans le cas du frontend, la version \texttt{latest} est utilisée sauf si une variable d'environnement \texttt{FRONTEND\_IMAGE\_VERSION} est définie.
\begin{listing}[H]
\begin{minted}[breaklines, linenos, tabsize=2, highlightlines={11,17}]{yaml}
networks:
traefik_network:
name: traefik_network
driver_opts:
com.docker.network.bridge.name: traefik_network
services:
frontend:
container_name: app-frontend
# {...} is replacing "beescreens/beescreens" to make URL shorter
image: registry.gitlab.com/{...}/app-frontend:${FRONTEND_IMAGE_VERSION:-latest}
restart: unless-stopped
env_file:
- common.env
- frontend.env
networks:
- traefik_network
expose:
- 4000
labels:
# Traefik configuration here
backend:
container_name: app-backend
# ...
\end{minted}
\caption{Fichier \texttt{docker-compose.yaml} d'exemple d'une application \gls{javascript}}
\label{listing:docker-compose-example-app}
\end{listing}
La configuration de Traefik~\cite{traefik} a volontairement été omise dans le listing \ref{listing:docker-compose-example-app} afin de ne pas surcharger le code. Traefik est un reverse proxy qui permet de rediriger les requêtes HTTP vers les bons services. Il est utilisé dans le cadre de ce projet afin de pouvoir accéder aux applications depuis l'extérieur de la machine virtuelle. Pour ce faire, tous les services sont ajoutés au réseau Traefik comme le montre la ligne 17. Pour avoir un exemple concret, les requêtes vers \texttt{app.beescreens.ch} sont redirigées vers le port 4000 de l'application. Traefik s'occupe également des certificats afin de pouvoir utiliser le protocole HTTPS pour sécuriser les applications.
% \subsection{Lien avec le projet BeePlace}
% \label{sec:lien-avec-le-projet-beeplace}
% \gls{beeplace} est une nouvelle application indépendante des applications existantes du projet \gls{beescreens}. Cependant, comme expliqué précédemment, \gls{beescreens} étant un monorepo, l'application \gls{beeplace} doit être ajoutée au même dépôt.
% Le concept \gls{beeplace} se base sur les conclusions réalisées à propos de l'application existante, Pimp My Wall. La problématique est la suivante: Pimp My Wall est une application trop permissive. Les utilisateurs peuvent dessiner de manière entièrement libre sur la toile virtuelle et cela engendre des comportements inappropriés. Le public cible, les personnes présentes au Baleinev Festival, est relativement jeune et l'ambiance festive de la soirée amène plus facilement à des dérives. Comme les créations des festivaliers sont affichées en temps réel sur les murs de l'école, il est nécessaire de modérer les créations des utilisateurs. Cette modération est fastidieuse, peu gratifiante et demande beaucoup de temps.
% Afin de pallier à ce problème, l'idée de \gls{beeplace} est née. En imposant un délai entre la pose de pixels aux utilisateurs, ceux-ci seront moins enclins à réaliser des créations inadaptées car cela leur demanderait un effort plus conséquent. Dans le cas où des débordements auraient quand même lieu, la modération pourrait remettre à zéro une zone de la toile en quelques clics. Ce qui ferait perdre énormément de temps aux usagers problématiques et les dissuaderait de recommencer.
\section{Intégration}
Pour réaliser l'intégration de façon optimale, un guide~\cite{addapptobeescreens} créé par les personnes qui maintiennent le projet \gls{beescreens} explique les étapes à suivre afin d'ajouter une nouvelle application au répertoire.
\subsection{Création d'une nouvelle application}
La première étape consiste à créer le dossier de l'application dans le dossier \texttt{apps} décrit précédemment. Dans celui-ci, deux dossiers sont également créés, un par service de l'application: \texttt{frontend} et \texttt{backend}. Le premier contient le code source de l'application côté client tandis que le second contient le code source de l'application côté serveur. D'éventuels autres dossiers seront peut être nécessaires en fonction des besoins de l'application. Ceux-ci seront créés après l'analyse préliminaire permettant de choisir les technologies utilisées.
L'arborescence est donc actuellement illustrée par le listing~\ref{listing:beeplace-repo-structure}.
\begin{listing}[H]
\begin{tcolorbox}[arc=0mm,colback=white!5!white]
\dirtree{%
.1 /.
.2 apps.
.3 beeplace.
.4 backend.
.4 frontend.
.3 ....
.2 ....
}
\end{tcolorbox}
\caption{Structure du répertoire de l'application BeePlace}
\label{listing:beeplace-repo-structure}
\end{listing}
Par la suite, un fichier \texttt{package.json} est nécessaire par dossier. Ces fichiers sont normalement utilisés dans les projets \gls{javascript} et \gls{nodejs} afin de préciser notamment les scripts, les dépendances et diverses métadonnées du projet. Dans ce cas-ci, ils sont utilisés peu importe les technologies qui seront choisies pour ce projet. En effet, cela permet d'unifier beaucoup d'aspects sur l'entièreté du code \gls{beescreens}. Par exemple, il est possible de lancer les tests unitaires de toutes les applications. Si la future application n'est pas développée en \gls{javascript}, les scripts du \texttt{package.json} lanceront les commandes nécessaires dans le langage souhaité afin d'abstraire le plus possible les technologies utilisées.
La structure des fichiers \texttt{package.json} est basée sur celle suggérée par les mainteneurs \gls{beescreens}~\cite{aboutpnpmbeescreens}. Comme les technologies ne sont pas encore définies, de nombreuses clés sont omises pour l'instant. La structure actuelle est visible dans le listing~\ref{listing:beeplace-backend-package-json}.
\begin{listing}[H]
\inputminted[tabsize=4, linenos]{json}{assets/figures/package.json}
\caption{package.json initial du backend l'application BeePlace}
\label{listing:beeplace-backend-package-json}
\end{listing}
Celui du frontend suit la même structure. Un script de test a été ajouté afin de vérifier que l'intégration est réussie par la suite.
Un dossier ainsi qu'un fichier \texttt{package.json} peuvent être créés dans le dossier \texttt{packages} si du code doit être partagé entre les diverses parties de l'application. Ce besoin n'a pas encore été identifié, donc aucun package n'a pour le moment été créé.
\subsection{Ajouter l'application au monorepo}
Afin de prévenir \gls{pnpm} qu'une nouvelle application a été ajoutée à la workspace, il faut modifier le fichier \texttt{pnpm-workspace.yaml} présent à la racine du répertoire en ajoutant les chemins vers les deux applications créées précédemment.
Grâce à cela, il est possible de lancer les tests précédemment créés en filtrant sur les applications souhaitées afin d'observer les résultats affichés dans le terminal.
\begin{listing}[H]
\begin{minted}{bash}
pnpm \
--filter @beescreens/beeplace-backend \
--filter @beescreens/beeplace-frontend \
test
# Results
Scope: 2 of 11 workspace projects
apps/beeplace/frontend test$ echo "This is a test from BeePlace Frontend!"
│ This is a test from BeePlace Frontend!
└─ Done in 9ms
apps/beeplace/backend test$ echo "This is a test from BeePlace Backend!"
│ This is a test from BeePlace Backend!
└─ Done in 9ms
\end{minted}
\caption{Lancement des tests de l'application BeePlace}
\label{listing:beeplace-tests}
\end{listing}
Afin d'être sûr que l'\gls{ide} Visual Studio Code ait connaissance de la nouvelle application, il est également nécessaire d'ajouter les chemins dans le fichier de configuration \texttt{.vscode/settings.json} présent à la racine du répertoire.
\subsection{CI/CD}
L'application doit être intégrées à deux pipelines: la locale gérée via Husky et la pipeline en ligne de \gls{gitlab}. Pour la première, il faut ajouter au fichier \texttt{.husky/pre-push} le code visible sur le listing \ref{listing:husky-tests} afin de lancer les tests avant chaque push.
\begin{listing}[H]
\begin{minted}[linenos]{bash}
## BeePlace
if
did_files_change_in_directory "apps/beeplace/**/*"
then
## test
pnpm --parallel \
--filter @beescreens/beeplace-backend \
--filter @beescreens/beeplace-frontend \
test
fi
\end{minted}
\caption{Lancement des tests de BeePlace avant chaque push avec Husky}
\label{listing:husky-tests}
\end{listing}
Grâce à la fonction \texttt{did\_files\_change\_in\_directory}, les tests ne seront lancés que si des fichiers ont été modifiés dans le dossier de l'application.
Pour la pipeline \gls{gitlab}, il faut tout d'abord créer un nouveau fichier \texttt{.gitlab/ci\_cd/\\beeplace.yml} visible dans le listing \ref{listing:gitlab-beeplace-tests}. Celui-ci contient les différentes étapes de la pipeline. Pour l'instant, il n'y a que la première étape qui est nécessaire: le lancement des "tests".
\begin{listing}[H]
\begin{minted}[linenos]{yaml}
## Backend
# test
beeplace::app::backend::test:
needs:
- setup env
extends: .test
variables:
PROJECT_PATH: "apps/beeplace/backend"
PROJECT_NAME: "@beescreens/beeplace-backend"
script:
- echo "Testing $PROJECT_NAME..."
## Frontend
# test
beeplace::app::frontend::test:
needs:
- setup env
extends: .test
variables:
PROJECT_PATH: "apps/beeplace/frontend"
PROJECT_NAME: "@beescreens/beeplace-frontend"
script:
- echo "Testing $PROJECT_NAME..."
\end{minted}
\caption{Lancement des tests de BeePlace dans la pipeline GitLab}
\label{listing:gitlab-beeplace-tests}
\end{listing}
Ce fichier doit être inclus dans le fichier \texttt{.gitlab/ci\_cd/main.yml} afin d'être ajouté à la pipeline globale.
L'application est maintenant prête à être développée. Le code peut être push afin de lancer les "tests" en local avec Husky et sur la pipeline \gls{gitlab}.