Qualité de Développement - R4.02

Deuxième mise en pratique du TDD.

Afin de continuer la mise en pratique du TDD et de poursuivre la prise en main du langage Rust, vous allez développer une petite bibliothèque de géométrie permettant de manipuler des points et des vecteurs 2D.

Création de la branche, de la merge request et du package Rust

Si ce n’est pas déjà fait, créez et basculez sur une nouvelle branche nommée geometry.

Créez la merge request correspondant à l’intégration de la bibliothèque de géométrie dans la branche principale.

Mettez bien à jour votre dépôt local, notamment en ce qui concerne les branches. Assurez-vous à ce stade de bien être sur la branche geometry.

Créez ensuite le package Rust tp3_geometry, de type blibliothèque avec la commande :

cargo new --lib tp3_geometry
Package de type bibliothèque

Le package que vous venez de créer est de type bibliothèque. Il ne contient pas de main.rs. Vous ne pouvez donc pas lancer d’exécution. Votre code ira dans le fichier lib.rs.

Vous pouvez constater qu’en revanche le squelette de tests est déjà présent dans ce fichier. C’est donc dans le fichier lib.rs que vous allez ajouter les fonctionnalités demandées ainsi que les tests correspondant.

Mise à jour du pipeline

Ajoutez dans le fichier .gitlab-ci.yml la configuration pour le "job" de test de la bibliothèque de géométrie. Ce job sera très similaire à celui du palindrome.

Validation du pipeline

Commitez et poussez votre code vers votre dépôt GitLab. Validez que le pipeline se déclenche bien et que les tests passent.

Mise en pratique du TDD sur la bibliothèque geometry

Pour rappel, les règles du TDD :
  1. Vous devez écrire un test qui échoue avant de pouvoir écrire le code de production correspondant.

  2. Vous devez écrire une seule assertion à la fois, qui fait échouer le test ou qui échoue à la compilation.

  3. Vous devez écrire le minimum de code de production pour que l’assertion du test actuellement en échec soit satisfaite.

Structures de données

Avant de commencer à ajouter des fonctionnalités à votre bibliothèque, définissez la structure de données Vec2D avec deux composantes, x et y, de type flottant sur 64 bits : f64.

Définissez également une structure Point avec les mêmes caractéristiques.

Vous pouvez consulter le chapitre du livre à ce sujet.

Fonctionnalités attendues
Créations
  1. Des fonctions associées au type Vec2D doivent permettre de créer :

    1. nul : un vecteur nul,

    2. new : un vecteur à partir de deux flottants donnés en paramètre,

    3. from_points : un vecteur à partir de deux points.

  2. Des fonctions associées au type Point doivent permettre de créer :

    1. origin : Un point d’origine avec les coordonnées (0.0, 0.0),

    2. new : Un point à partir des coordonnées données en paramètre.

Opérations : écrire les fonctions suivantes :
  1. add : ajouter deux vecteurs,

  2. translate : déplacer un point en fonction d’un vecteur donné,

  3. norm : calculer la norme d’un vecteur,

  4. scale : appliquer une homothétie à un vecteur,

  5. normalize : normaliser un vecteur,

  6. rotate : appliquer une rotation à un vecteur,

  7. angle : calculer l’angle entre deux vecteurs,

  8. dot : calculer le produit scalaire entre deux vecteurs,

  9. colinear : déterminer si deux vecteurs sont co-linéaires,

Appliquez les règles du TDD pour réaliser les fonctionnalités demandées.

Commencez par écrire le test qui valide la création d’un vecteur :

#[test]
fn new_is_valid() {
    let u = Vec2D::new(31.0, 11.0);
    assert_eq!(u.x, 31.0);
    assert_eq!(u.y, 11.0);
}

Le compilateur doit vous insulter puisque vous n’avez pas encore créé cette fonction. Pour satisfaire le compilateur, créez la fonction associée new (qui n’est pas strictement un constructeur puisque cela n’existe pas en Rust) dans un bloc impl Vec2D.

Une fois que cela fonctionne, créez le test pour la fonction pour le vecteur nul, puis la fonction de création nul.

Et ainsi de suite.

Pensez à faire un commit à chaque itération ! C’est-à-dire à chaque fin du cycle TDD.

Structuration du code

Une fois ce processus terminé, pour améliorer la qualité de votre bibliothèque en terme de lisibilité et donc de maintenabilité, vous allez structurer votre code.

Commencez en plaçant les éléments relatifs au type Vec2D dans un module dédié. Consultez la page pertinente dans le livre de Rust

Il vous faudra créer deux modules : vec2d et point.

Pour créer un module, vous avez deux options :

  • Créer un fichier nom_module.rs au même niveau que le fichier lib.rs ou

  • Créer un répertoire nom_module au même niveau que le fichier lib.rs et dans ce répertoire, créer un fichier mod.rs.

Pour que le compilateur prenne en compte ces nouveaux modules, il faudra ajouter en haut du fichier lib.rs : mod nom_module.

Pour pouvoir utiliser les fonctions définies dans votre module, vous devez ajouter :

use nom_module::NomType;

Vous pourrez ensuite utiliser les fonctions de votre type avec :

NomType::uneFonction();

Chaînage des opérations

L’objectif ici est de rendre possible le chaînage des opérations :

let mut p = Point::origin();
let mut v = Vec2D::new(12.3, 45,6);
p.translate(v.scale(3.0).rotate(PI).add(Vec2D::new(1.0, 1.0)));

Pour cela, il faudra que les opérations de modification retournent une référence vers le vecteur modifié.

Évaluation

Seule la partie sur la bibliothèque "geometry" sera évaluée.

Les critères d’évaluation sont les suivants :
  • Présence de tests pour valider les fonctionnalités et notamment les cas limites (translation par un vecteur nul, rotation d’un angle de 2π).

  • Organisation du code :

    • Modules placés dans des fichiers ou répertoires dédiés et formant des unités logicielles cohérentes.

    • Cohérence et uniformité dans l’organisation des déclarations de structures et de fonction associées.

  • Documentation des modules, structures et fonctions.

    • Idéalement en ajoutant des exemples d’utilisation qui passeront en tests.

  • Respect de la norme de codage Rust (formatage).

  • Réalisation des fonctionnalités demandées.

  • Réalisation d’un Readme décrivant rapidement la bibliothèque et pointant vers la documentation générée.

  • Présence de la documentation générée dans le dépôt Git, dans le répertoire "doc".

Seul ce qui aura été fusionné (merged) dans la branche main sera évalué. Idéalement avec un tag pour marquer la fin du travail.