Aller au contenu principal

TP 4

Objectifs

Durée : 30 minutes

Dans la suite de notre besoin "fil rouge".

On veut faire une librairie TypeScript pour notre librairie d'affichage web de documents Data.

Le module doit pouvoir recevoir en entrée plusieurs types de fichiers : Excel, CSV, Json

Dans le cas du fichier Excel, on ne prend pas en compte le fait qu'il y ait plusieurs feuilles.

Le module doit sortir un format normalisé commun : un tableau standard sérialisable en JSON.

On veut que le module expose une fonction unique de conversion.

Le module doit pouvoir être extensible à d'autres formats à l'avenir (ex: Parquet).

L'équipe de tests recommande le framework Jest pour les tests unitairs TypeScript.


Contraintes

Vous êtes libres d'utiliser l'outil de votre choix.

Si vous préférez utiliser un autre langage que TypeScript, vous pouvez.

Vous devez essayer de fournir le code final du module. Mais on est en mode atelier :)


Etape 1 : Produire les documents de référence

Construire un jeu de recommandations qui intègre des contraintes :

  • d'architecture logicielle
  • de testabilité
  • de sécurité
  • autres selon votre envie
Indice
<contraintes>

# Fonctionnelles
On veut faire une librairie TypeScript pour notre librairie d'affichage web de documents Data.
Le module doit pouvoir recevoir en entrée plusieurs types de fichiers : Excel, CSV, Json
Dans le cas du fichier Excel, on ne prend pas en compte le fait qu'il y ait plusieurs feuilles.
Le module doit sortir un format normalisé commun : un tableau standard sérialisable en JSON.
On veut que le module expose une fonction unique de conversion.
Le module doit pouvoir être extensible à d'autres formats à l'avenir (ex: Parquet).
L'équipe de tests recommande le framework Jest pour les tests unitairs TypeScript.

# Architecture
Adopter l'architecture hexagonale pour séparer le cœur métier des dépendances externes (bases de données, API, UI), en utilisant des ports et des adaptateurs.
Implémenter l'injection de dépendances pour gérer les dépendances de manière dynamique et découpler les composants.
Appliquer le Domain-Driven Design (DDD) pour modéliser les règles métier complexes et structurer l'architecture autour des entités et des domaines.
Utiliser le pattern de service (Service Layer) pour regrouper la logique métier et isoler les couches de présentation et de persistance.
Respecter le principe de responsabilité unique (Single Responsibility Principle) pour maintenir la modularité et la maintenabilité du code.
Appliquer le principe Open/Closed (ouverture aux extensions, fermeture aux modifications) pour permettre l'ajout de nouvelles fonctionnalités sans altérer l'existence.
Concevoir des interfaces claires et testables, en favorisant l'abstraction pour faciliter le mocking et les tests unitaires.
Utiliser le pattern Strategy pour encapsuler des algorithmes interchangeables et éviter la duplication de code logique.

# Tests
Chaque test unitaire doit valider une seule fonctionnalité ou un seul cas de figure.
Un test unitaire ne doit pas vérifier à la fois la logique d'une fonction et son interaction avec une base de données.
Les tests unitaires doivent être indépendants les uns des autres.
Utiliser des mocks ou des stubs pour isoler les dépendances (ex. API externe, bases de données).
Ne pas partager des états entre les tests (ex. variables globales, données de test).
Les tests unitaires doivent être reproductibles et ne pas dépendre de l'ordre d'exécution.
Suivre le principe AAA (Arrange, Act, Assert) pour structurer les tests.
Les tests unitaires doivent valider les scénarios attendus (ex. une fonction qui renvoie un résultat prévu).
Tester les cas limites de la plage de valeurs (ex. 0, -1, 1000, etc.).
Vérifier que les erreurs sont levées correctement (ex. division par zéro, paramètres invalides).
Tester les comportements des dépendances (ex. appel d'une API, lecture d'un fichier).
Les développeurs négligent souvent de tester les cas d'erreur non gérés (ex. entrées invalides, fichiers corrompus).
Ajouter des tests pour chaque cas d'erreur possible.
Les tests unitaires ne mesurent pas la performance (ex. temps d'exécution).
Les tests unitaires ne vérifient pas les aspects de sécurité (ex. injection SQL, attaques XSS).
Réutiliser des tests via des méthodes ou des fonctions de test partagées.
</contraintes>


Etape 2 : Produire l'arborescence du dossier et la signature du code

En fournissant les recommandations et le besoin, obtenez:

  • l'architecture du module en fichiers de code plus classes
  • le fichier header avec les signatures de classe(s)
Indice

<contraintes>
...
</contraintes>

<task>
En tant que <role/>, travaillant dans une équipe de développement logiciel professionnel.

En utilisant les frameworks <frameworks/>, je dois accompllir la tache <tache/>

Je dois respecter les contraintes fonctionnelles et techniques suivantes : <contraintes définies dans le fichier docs/architecture.md>

Je dois respecter la recommandation de sortie suivante : <type de tache ou de sortie attendue />

Attention ! Tu ne dois pas remplir les rôles de XXX ou YYY !

</task>

Etape 3 : Produire le fichier de tests

Créez et lancez le prompt testeur pour obtenir la classe de tests.


Etape 4 : Produire le fichier de la librairie

Créez et lancez le prompt développeur pour obtenir la classe de code.


Avancé

Obtenez

  • des jeux de test en entrée / sortie (XML, Json)
  • Exécutez les tests dans un shell

Fabriquez une image Docker capable de lancer les tests sur la librairie.


Analyse

Il est difficile d'arriver à tout faire en temps imparti.

Pensez-vous que ce soit réalisable avec un temps suffisant ? Optimal ?

Quels seraient les avantages ?

Qu'est-ce qui manque ?