-- Présentation --
Fitness-inator est une application web de suivi sportif personnel, permettant d'enregistrer des séances d'entraînement, de gérer des exercices, et de visualiser sa progression dans le temps. Pas de client fictif, pas d'énoncé d'examen, pas de stack imposée. Un projet né d'une décision simple : construire quelque chose de concret pour pratiquer TypeScript en dehors du cadre académique, sur un domaine connu et motivant.
C'est un projet personnel, réalisé seul, entièrement autodidacte dans sa conception et son exécution. Aucune grille d'évaluation, aucun délai externe, aucune contrainte imposée par un tiers. La seule exigence : produire une application réelle, fonctionnelle, codée proprement, qui aurait pu être utilisée au quotidien. Ce type de projet révèle plus honnêtement le niveau d'un développeur qu'un examen, parce que personne ne définit les règles du jeu à sa place.
-- Objectifs --
L'objectif était double. Fonctionnellement : construire un outil de suivi sportif utilisable au quotidien, capable d'enregistrer des séances, de gérer une bibliothèque d'exercices, et de donner une vision claire de la progression sur la durée. Techniquement : pratiquer TypeScript en profondeur, au-delà de ce que les projets académiques permettent, en faisant tous les choix de typage à la main, sans la structure imposée par un framework fortement opinioné.
Le contexte était celui d'un développeur en alternance qui avance sur ses compétences en dehors des heures de cours et des projets d'examen. Le temps disponible est limité, la motivation doit être suffisamment forte pour tenir dans la durée sans deadline externe. Choisir un domaine personnel, le sport, comme terrain d'application n'était pas anodin : la motivation de construire un outil qu'on va soi-même utiliser est structurellement plus stable que la motivation de livrer un projet fictif pour une note.
L'enjeu principal était la qualité intrinsèque du code. Sur un projet personnel sans évaluateur, la tentation des raccourcis est permanente. Un `any` TypeScript "pour aller plus vite", un composant trop large "pour l'instant", une fonction qui fait trois choses "parce que c'est plus simple". Résister à ces compromis sur un projet où personne ne contrôle, c'est l'enjeu réel. Pas la fonctionnalité, la discipline.
Les risques étaient essentiellement motivationnels et organisationnels. Un projet personnel sans deadline peut s'étirer indéfiniment, perdre de sa substance au fil des semaines, et finir en demi-mesure. Le risque de scope creep était aussi présent : les fonctionnalités possibles sur une application de suivi sportif sont nombreuses, et l'envie d'en ajouter toujours plus pouvait empêcher de finir proprement ce qui était déjà commencé. Définir un périmètre stable et s'y tenir était une contrainte auto-imposée indispensable.
-- Étapes --
Phase 1 : Définition du périmètre et des choix techniques
Avant d'écrire la première ligne de code, le périmètre fonctionnel a été fixé par écrit. Trois modules principaux : gestion des exercices (bibliothèque personnelle avec nom, groupe musculaire, description), gestion des séances (création d'une séance avec date, liste d'exercices réalisés, séries, répétitions, charges), et visualisation de la progression (évolution des charges sur un exercice donné dans le temps). Ce périmètre, une fois défini, n'a pas bougé. Les idées d'ajout qui sont venues en cours de développement ont été notées pour une version future, pas intégrées immédiatement.
La stack a été choisie pour correspondre à l'objectif d'apprentissage. TypeScript comme contrainte centrale, un framework frontend moderne pour travailler dans un contexte réaliste, une gestion d'état pensée pour que les interfaces de données soient définies une fois et réutilisées partout. Chaque choix technique a été justifié par l'objectif d'apprentissage, pas par la facilité ou la vitesse.
Phase 2 : Modélisation des types TypeScript
La phase de modélisation des types a été traitée comme une phase de conception à part entière, pas comme une formalité. Chaque entité du domaine a été typée avec précision : un exercice avec son identifiant, son nom, son groupe musculaire, sa description optionnelle. Une série avec ses répétitions, sa charge et son unité. Un exercice de séance qui agrège un exercice de la bibliothèque et ses séries réalisées. Une séance avec sa date, sa durée optionnelle, sa liste d'exercices réalisés.
Les types union ont été utilisés pour les états possibles d'un exercice (en cours, terminé), les types intersection pour combiner des propriétés communes, les génériques pour les fonctions utilitaires réutilisables sur plusieurs types d'entités. L'objectif était de rendre impossible, par construction, la création d'un objet incohérent. Un composant qui reçoit un exercice de séance ne peut pas accidentellement accéder à des propriétés qui n'existent que sur un exercice de bibliothèque. TypeScript garantit cette séparation à la compilation.
Phase 3 : Architecture des composants
L'architecture des composants a été pensée selon le principe de responsabilité unique. Chaque composant fait une seule chose et la fait bien. Le composant de liste d'exercices affiche, il ne modifie pas. Le composant de formulaire d'exercice modifie, il n'affiche pas la liste. Le composant de visualisation de progression reçoit des données traitées, il ne fait pas lui-même les calculs d'agrégation.
Cette séparation a rendu chaque composant testable indépendamment et modifiable sans risque de régression sur les autres. Sur un projet personnel où on est à la fois le développeur et l'utilisateur, cette rigueur peut sembler excessive. C'est exactement l'inverse : c'est dans ces moments sans contrainte externe que les bonnes habitudes se confirment ou s'abandonnent.
Phase 4 : Gestion de l'état et persistance
La gestion de l'état a été conçue pour que les interfaces TypeScript définies en phase 2 soient respectées à chaque couche de l'application. Les fonctions de lecture et d'écriture des données sont toutes typées explicitement : une fonction qui retourne des séances retourne un tableau de type `Seance[]`, jamais un `any[]`. Les erreurs de type sont détectées à la compilation, pas à l'exécution.
La persistance des données a été implémentée pour que l'application reste utilisable entre les sessions. Les séances enregistrées, la bibliothèque d'exercices construite au fil du temps : ces données ont de la valeur uniquement si elles survivent au rechargement de la page. Cette exigence fonctionnelle simple a imposé de réfléchir à la sérialisation et désérialisation des types TypeScript, un exercice concret sur les limites du typage statique face aux données dynamiques.
Phase 5 : Visualisation de la progression
La visualisation de la progression a été la fonctionnalité la plus intéressante techniquement. Afficher l'évolution d'une charge maximale sur un exercice donné à travers le temps implique d'agréger des données issues de plusieurs séances, d'extraire les valeurs pertinentes, et de les présenter sous une forme lisible. Ce traitement de données a été entièrement typé : les fonctions d'agrégation prennent des types précis en entrée et retournent des types précis en sortie, ce qui rend leur comportement prévisible et vérifiable.
Le rendu graphique a été intégré via une librairie de visualisation compatible TypeScript, ce qui a été l'occasion de travailler sur l'intégration d'une dépendance externe dans un projet typé : comprendre les types exposés par la librairie, les étendre si nécessaire, garantir que les données passées au composant graphique correspondent exactement à ce qu'il attend.
Phase 6 : Revue et refactorisation
Une fois les fonctionnalités principales terminées, une passe de revue complète du code a été effectuée. Chaque `any` résiduel a été traqué et remplacé. Chaque fonction trop longue a été découpée. Chaque composant qui faisait plus d'une chose a été refactorisé. Cette phase de refactorisation, souvent négligée sur les projets sous pression, a été traitée comme une étape à part entière, parce que c'est précisément l'objectif du projet : produire du code dont on est fier, pas du code qui fonctionne en attendant d'être revu.
-- Acteurs --
Fitness-inator est un projet sans aucun acteur externe. Pas de client, pas d'évaluateur, pas d'équipe, pas de pair pour relire le code. La seule interaction significative a été avec la documentation des technologies utilisées, les exemples de la communauté TypeScript, et les retours du compilateur lui-même.
Cette configuration entièrement solo est à la fois la force et la limite de ce projet. La force : chaque décision est pleinement assumée, chaque ligne de code reflète directement les convictions du développeur sur ce que doit être un code de qualité. La limite : sans regard extérieur, certains angles morts restent invisibles. Une architecture qui semble évidente quand on l'a conçue soi-même peut s'avérer difficile à appréhender pour quelqu'un d'autre. Ce manque de regard externe est la principale lacune de tout projet personnel conduit en solo.
-- Résultats --
Pour le développeur : Fitness-inator a produit exactement ce qu'il était censé produire : une maîtrise plus profonde de TypeScript, acquise par la pratique sur un vrai projet fonctionnel. Les types avancés, les génériques, la gestion des cas limites du système de types, l'intégration de librairies externes dans un contexte fortement typé : ces sujets ont été travaillés concrètement, pas théoriquement. La progression sur TypeScript entre le début et la fin de ce projet est mesurable dans la qualité du code produit.
La discipline maintenue tout au long du projet, en l'absence de toute contrainte externe, est aussi un résultat en soi. Finir proprement un projet personnel, sans relâcher les standards quand personne ne regarde, c'est la preuve que les bonnes pratiques sont intégrées, pas performées. C'est une distinction qui compte vraiment dans la durée.
-- Lendemains --
Dans un futur immédiat, plusieurs fonctionnalités identifiées en cours de développement et délibérément mises de côté pour ne pas dériver du périmètre initial attendaient d'être traitées : un système de programmes d'entraînement prédéfinis, une vue de calendrier pour visualiser la régularité des séances, des statistiques plus riches sur les volumes d'entraînement par groupe musculaire. Ces évolutions étaient documentées, prêtes à être implémentées sur une V2 sans avoir à tout repenser.
À distance, Fitness-inator a posé une base réutilisable sur la modélisation de domaines avec des données temporelles et des agrégations. Le pattern de traitement des séries chronologiques pour en extraire des tendances, appliqué ici à la progression sportive, est directement transposable à d'autres contextes : suivi de métriques financières, analytics d'usage d'une application, tableaux de bord de performance. La réflexion de fond sur les types TypeScript adaptés à ce genre de données a une portée bien au-delà du domaine sportif.
Aujourd'hui, Fitness-inator est sur le portfolio comme démonstration d'une initiative personnelle et d'une pratique volontaire de TypeScript. Dans un secteur où beaucoup de développeurs ne codent que sur ce qui leur est demandé, un projet personnel fonctionnel construit par conviction envoie un signal différent : celui d'un développeur qui continue d'apprendre et de construire même quand rien ne l'y oblige.
-- Regard critique --
Fitness-inator est le projet sur lequel l'honnêteté est la plus simple, parce que les attentes étaient les plus claires. L'objectif était de pratiquer TypeScript sur un vrai projet. Cet objectif a été atteint. Ce qui ne signifie pas que tout était parfait.
Le manque de tests est le point le plus évident à critiquer. Sur un projet académique, la couverture de tests est une exigence de la grille. Sur un projet personnel, elle devient optionnelle de fait. Et cette optionnalité a été utilisée : Fitness-inator n'a pas de suite de tests automatisés. C'est une incohérence avec les valeurs affichées par ailleurs sur la qualité du code. Un code bien typé et bien structuré sans tests reste fragile : une refactorisation peut casser un comportement sans que rien ne le détecte. Ce manque est assumé et identifié comme la première chose à corriger sur une V2.
L'absence de regard extérieur a aussi ses limites visibles. L'architecture des composants semble évidente quand on est l'auteur. À froid, avec du recul, certains choix de découpage auraient pu être questionnés par un pair. Il y a probablement des endroits où la séparation des responsabilités n'est pas aussi propre qu'elle le paraissait au moment de l'écriture. Soumettre ce code à une vraie revue de code serait le prochain exercice utile.
Ce qui reste de plus précieux dans ce projet n'est pas la fonctionnalité ni le code. C'est la preuve, pour soi-même, que la motivation de bien faire existe indépendamment de la contrainte externe. C'est peut-être la chose la plus difficile à démontrer sur un portfolio, et la plus convaincante quand elle est réelle.